Skip to content
Home Projects Traffic Analysis
🚗 Traffic Analysis Python Data Visualization 2018-2020 Dataset

17,312 Tweets About Traffic, And What They Are Not

Every incident MMDA posted between 2018-08-20 and 2020-12-27. Half of them are in one city and 146 days in the span have no report at all — so this measures a Twitter account, not a road network. What it does capture is 15 March 2020, when the daily rate fell from 28.24 to 3.12.

17,312
Incident reports, 2018-08-20 to 2020-12-27
50.4%
Of them in Quezon City alone
89.0%
Fall in the daily rate under lockdown
12.0
National road deaths per 100,000, 2019
Data Period
August 2018 - December 2020
Tech Stack
Python Pandas Chart.js HTML/CSS
Key Takeaways

This is a record of what MMDA tweeted, and the distribution proves it: 50.4% of all 17,312 incidents are in Quezon City, 91.59% are in four cities, and Navotas has 3 in two and a half years.

  • The previous version of this page reported “15 Cities/Areas”. The column holds 15 distinct strings but two are the same city: “Parañaque” also appears as “Parañaque” in 107 rows, its UTF-8 bytes read as Latin-1. There are 14 cities, and Metro Manila has 17 — 3 never appear.
  • 55 rows are geocoded to exactly 0,0, which is in the Gulf of Guinea. 138 have a time that does not parse, including “22:55 PM”. 2 months contain no rows at all.
  • The lockdown is the cleanest signal in the file: 28.24 incidents per reporting day before 15 March 2020, 3.12 during ECQ, and 10.74 afterwards — still 62.0% below where it started when the data ends.
  • The morning peak is worse than the evening one: 28.14% of timed incidents fall in 06:00–09:59 against 19.98% in 16:00–19:59. The sharpest trough is 1pm, at 558 against 1,354 at 7am.
  • Nationally, road deaths run at 12.0 per 100,000 — 3rd lowest of 6 in ASEAN. But it is up 22.4% since 2000, and only 2 of the six moved that way.

Half The File Is One City

Incidents by city, after repairing the encoding. This is not a ranking of dangerous places — it is a ranking of which MMDA units post to Twitter, and it is the single most important thing to know before reading anything else here.

Incidents by city, share of the whole file

Quezon City
50.4%

8,725 of 17,312 incidents. Four cities carry 91.59% between them.

Cities present
14 of 17

Metro Manila has 17 local government units; 3 never appear in the file. The published figure of 15 counted Parañaque twice.

Navotas
3

Incidents in two and a half years. Not a safe city — an unreported one.

Fifteen March 2020

Metro Manila entered enhanced community quarantine on 15 March 2020 and stayed under ECQ or MECQ until 31 May. Rates are per reporting day, not per calendar day, because the account goes quiet for stretches and dividing by calendar days would blame the roads for a silent feed.

Incidents per month, with months that have no rows marked

Before
28.24/day

2018-08-20 to 14 March 2020.

Under ECQ and MECQ
3.12/day

A fall of 89.0%. February had 775 incidents; April had 11.

After
10.74/day

Through to 2020-12-27 — still 62.0% below the pre-lockdown rate seven months later.

The Morning Is Worse Than The Evening

Incidents by hour, across the 17,174 rows with a time that parses. Two things stand out: the morning peak is larger than the evening one, and 1pm is a deeper trough than any hour either side of it.

Incidents by hour of day, share of timed reports

Peak hour
7:00

1,354 incidents, 7.88% of all timed reports.

Morning against evening
28.14% vs 19.98%

06:00–09:59 against 16:00–19:59, a gap of 8.16 points.

The 1pm trough
558

Against 1,354 at the 7am peak — 41.2% of it. The quietest hour is 2:00 with 57.

And Sunday Is Half A Tuesday

Incidents per reporting day by weekday. Dividing by reporting days rather than totals matters here: Sunday has fewer reporting days as well as fewer incidents, and a raw total would confuse the two.

Incidents per reporting day, by weekday

Tuesday
27.79/day

The busiest weekday.

Sunday
13.15/day

47.3% of Tuesday. The weekday-to-weekend difference is the clearest ordinary pattern in the file.

Silent days
146

Days inside the 861-day span with no report at all. Metro Manila did not have 146 incident-free days.

What Counts As An Incident

The type column is free text, not a code list: 478 distinct strings across 17,312 rows, including at least five misspellings of “vehicular”. Grouping by substring rather than by exact match is why the family totals differ from the published figure of 11,781, which matched neither.

Incidents by type family

Vehicular accidents
68.26%

11,818 incidents across 26 distinct spellings.

Stalled vehicles
22.85%

3,956 incidents across 276 spellings — mostly “STALLED <vehicle> DUE TO MECHANICAL PROBLEM” with the vehicle changing.

Distinct raw strings
478

Grouped into 7 families by what the string says, so a new vehicle in a later vintage lands in the right family rather than falling out. The families also catch protests and DPWH road works, which MMDA reports as traffic incidents.

EDSA Is Half Of Everything

The most-reported locations, all of them on two roads. EDSA alone accounts for nearly half of every located incident, which is partly about EDSA and partly about where MMDA has cameras and enforcers.

Most-reported locations

EDSA SHAW TUNNEL
306

In Mandaluyong. The single most-reported spot in the file.

EDSA's share
48.04%

8,306 incidents on one road, out of every row that names a location.

Distinct locations
2,959

Free text again, so “EDSA GUADALUPE” and “EDSA GUADALUPE NB” are two entries. The count is an upper bound on distinct places.

What The Country Looks Like Instead

WHO estimates of road traffic deaths per 100,000, for the Philippines and five ASEAN neighbours. These are national, annual and comparable — everything the tweets are not. They are also modelled rather than counted: WHO adjusts national registrations for known under-reporting.

Road traffic deaths per 100,000, 2000 onward

Philippines, 2019
12.0

Deaths per 100,000. 3rd lowest of 6.

Direction of travel
+22.4%

Since 2000, when it was 9.8. Only 2 of the six moved that way; the other is Vietnam.

Thailand
32.2

The highest of the six, and falling. A low rate that is rising and a high rate that is falling are different problems.

What This Data Cannot Say

Four limits, all of them structural rather than fixable.

It is not a count of incidents

It is a count of tweets. 146 of the 861 days in the span have no report at all and 2 whole months are empty, which means the series measures reporting activity and traffic together with no way to separate them. Every rate on this page is per reporting day for that reason.

There is no severity

The tweets say a vehicular accident occurred and how many lanes were blocked. They do not say whether anyone was hurt. A check asserts the injury and fatality counts stay at zero so a later column cannot quietly turn an incident count into a casualty figure.

There is no denominator

An incident count without traffic volume is not a rate. Quezon City has more reports than Navotas and also vastly more road, more vehicles and more MMDA presence; nothing here separates those. The national death rates in section 7 are per capita, which is a denominator, and they rank the cities differently than the tweet counts would.

It stops in December 2020

Which means the recovery from lockdown is only partly visible: the rate was still 62.0% below its pre-March level when the data ends, and whether it returned is outside this file.

Method

One fetcher, ten CSVs, and a coverage table that counts every fault rather than silently repairing it.

The encoding is repaired, not worked around

“Parañaque” is “Parañaque” whose UTF-8 bytes were decoded as Latin-1. Re-encoding to Latin-1 and decoding as UTF-8 reverses it exactly, and is applied only when the marker byte is present so a correct string is never touched. A check then fails if any double-encoded name survives, and another asserts Parañaque is one row rather than two.

Bad coordinates are blanked, not dropped

The 55 rows at exactly 0,0 are real incidents with a broken geocode. Dropping them would understate the counts; keeping the coordinate would put them in the Gulf of Guinea. The coordinate is cleared, the incident still counts, and a check asserts every surviving coordinate is inside a Metro Manila bounding box.

Times are parsed strictly

The file uses “7:55 AM”, “3:20PM” and bare “7:55”. One row reads “22:55 PM” — a 24-hour clock wearing a 12-hour marker — which a naive conversion turns into hour 34. That is how it was found. Anything that does not match an anchored pattern is recorded as unparseable rather than guessed at.

Empty months are rows, not gaps

The monthly table is built across the whole calendar span rather than over the months that happen to have data, so July and August 2020 appear as zero rows carrying a note. A check fails if a zero month has no note, because a chart that plots a reporting gap as zero is asserting something false.

Types are grouped by substring

478 distinct free-text strings, including VEHCICULAR, VEHICUKAR and VEHICHULAR ACCIDENT. Grouping on what the string contains rather than matching a hand-kept list means the misspellings land in the right family and a new vehicle in a later vintage does not fall out. A warn-level check lists the “vehicular” variants that still sort into “other”.

The national series comes through the World Bank

WHO Global Health Observatory road death estimates, fetched from the World Bank WDI API because it is reachable and returns a clean error on a wrong indicator code rather than an empty success.

Key Findings & Summary

  • 50.4% of the 17,312 incidents are in Quezon City and 91.59% in four cities, so this ranks MMDA's reporting rather than Metro Manila's roads.
  • “15 Cities/Areas” counted Parañaque twice, because 107 rows spell it “Parañaque”. There are 14 cities of a possible 17.
  • The lockdown cut the daily rate from 28.24 to 3.1289.0% — and it was still 62.0% down when the file ends.
  • Morning beats evening, 28.14% against 19.98%, and 1pm (558) is a sharper trough than either night. 13.15 per day on Sunday against 27.79 on Tuesday.
  • EDSA carries 48.04% of every located incident, on its own.
  • Nationally the death rate is 12.0 per 100,000, third lowest of 6 in ASEAN, but up 22.4% since 2000 — one of only 2 in the group moving that way.
  • 55 rows are geocoded to 0,0, 138 have no usable time, and 146 days in the span have no report at all.

Sources & Citations

Every figure on this page traces to one of these, through a CSV in data/ph-traffic/. Each is checked against its source query on every build.

17,312 incident reports scraped from the MMDA Twitter account, 20 August 2018 to 27 December 2020: date, time, city, location, coordinates, incident type, direction, lanes blocked, and the tweet text — A record of what MMDA tweeted, not a register of what happened. Quezon City alone is 50.4% of the file, 55 rows are geocoded to 0,0, and July and August 2020 contain no rows at all.

Estimated road traffic deaths per 100,000 population, 2000-2019, for the Philippines and five ASEAN neighbours — The national counterweight. Annual, comparable across countries, and modelled rather than counted -- WHO adjusts national registrations for known under-reporting.

The origin of every incident row; each row carries the status URL it came from — Cited for provenance. The tweets themselves were not re-fetched, and many of the linked statuses are no longer retrievable.

Have Data But Need Help?

If you have raw data and want to transform it into meaningful insights like this analysis, I'd love to help! Whether it's business data, research datasets, or any information you want to visualize and understand better.

Have a dataset you'd like analyzed or need a mini AI project as a starter guide? Send me your suggestions!

Connect on LinkedIn Dev.to Articles 💬 Messenger

Prefer the plain-English version?

I wrote a companion post — “A City Got Counted Twice, And 55 Crashes Landed In The Atlantic” — in simple, everyday words.

Read the blog post →