Characteristic NYC Neighborhood Complaints
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.
New York City month continues here at Kieran Healy Industries, an effort that will eventually produce something properly scholarly in nature. But in the meantime—and with my apologies to the many great urbanists of times past—we can enjoy ourselves by messing around with some data. Specifically, New York’s 311 Services and Complaints data. The 311 phone line and website is the the main point of contact for city services when it’s not an emergency. The city logs all the calls it gets and makes anonymized data available publicly via NYC OpenData. I got every record from 2010 to 2025 and packaged it up for R. The package is really just a front-end for a big parquet file managed by DuckDB. DuckDB offers a very powerful in-memory database engine that is optimized for the kinds of thing we want to do in data analysis. That is, we want to efficiently query a big dataset lots of different ways, rather than, say, repeatedly update its records as fast as possible. We can work in R and write tidy dplyr-like queries that get handled by the database. It’s great.
The dataset has about 43 million rows, each one of which is a service request (i.e., a complaint). I interact with it via a function that returns a DuckDB table. It looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
nyc_311() #> # A duckplyr data frame: 37 variables #> unique_key created_date closed_date agency agency_name problem problem_detail location_type incident_zip incident_address street_name cross_street_1 cross_street_2 address_type city status #> <dbl> <dttm> <dttm> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> #> 1 45278137 2019-12-31 23:59:11 2020-01-01 03:07:18 NYPD New York Cit… Noise … Banging/Pound… Club/Bar/Res… 11229 3939 EMMONS AVE… EMMONS AVE… PLUMB 3 ST… BELT PARKWAY … <NA> BROO… Closed #> 2 45281589 2019-12-31 23:58:54 2020-01-01 05:37:03 NYPD New York Cit… Noise … Loud Music/Pa… Residential … 10025 865 COLUMBUS AV… COLUMBUS A… WEST 100 STR… WEST 103 STR… <NA> NEW … Closed #> 3 45283574 2019-12-31 23:58:03 2020-01-01 01:26:50 NYPD New York Cit… Noise … Loud Music/Pa… Residential … 10040 558 WEST 192 S… WEST 192 … AUDUBON AVENUE ST NICHOLAS A… <NA> NEW … Closed #> 4 45278249 2019-12-31 23:57:19 2020-01-01 09:33:55 NYPD New York Cit… Noise … Loud Music/Pa… Residential … 11372 35-18 91 STREET 91 STREET 35 AVENUE 37 AVENUE <NA> JACK… Closed #> 5 45282332 2019-12-31 23:56:52 2020-01-01 03:06:36 NYPD New York Cit… Blocke… No Access Street/Sidew… 11226 2310 CORTELYOU … CORTELYOU … EAST 23 STR… BEDFORD AVENUE <NA> BROO… Closed #> 6 45281555 2019-12-31 23:56:34 2020-01-01 08:22:26 NYPD New York Cit… Noise … Loud Music/Pa… Residential … 11375 72-72 112 STREET 112 STREET 72 DRIVE 73 AVENUE <NA> FORE… Closed #> 7 45281053 2019-12-31 23:56:34 2020-01-01 02:47:53 NYPD New York Cit… Noise … Loud Music/Pa… Street/Sidew… 10128 EAST 89 STREET EAST 89 … 2 AVENUE 1 AVENUE <NA> <NA> Closed #> 8 45282921 2019-12-31 23:56:32 2020-01-01 02:18:56 NYPD New York Cit… Noise … Loud Music/Pa… Residential … 11433 168-70 93 AVENUE 93 AVENUE 168 PLACE 170 STREET <NA> JAMA… Closed #> 9 45283114 2019-12-31 23:56:28 2020-01-01 05:58:35 NYPD New York Cit… Noise … Loud Music/Pa… Residential … 11373 42-21 KETCHAM S… KETCHAM ST… BAXTER AVENUE PETTIT AVENUE <NA> ELMH… Closed #> 10 45281055 2019-12-31 23:55:56 2020-01-01 11:01:07 NYPD New York Cit… Noise … Loud Talking Street/Sidew… 11435 85-85 148 STREET 148 STREET 85 DRIVE 86 AVENUE <NA> JAMA… Closed #> # ℹ more rows #> # ℹ 21 more variables: resolution_description <chr>, resolution_action_updated_date <dttm>, community_board <chr>, police_precinct <int>, bbl <chr>, borough <chr>, open_data_channel_type <chr>, #> # park_facility_name <chr>, park_borough <chr>, latitude <dbl>, longitude <dbl>, created_year <dbl>, created_month <dbl>, created_day <dbl>, created_dow <chr>, created_hour <dbl>, closed_year <dbl>, #> # closed_month <dbl>, closed_day <dbl>, closed_dow <chr>, closed_hour <dbl> |
We can ask all kinds of questions of data like this. We also have to be careful with it, just because any dataset that’s this large and has grown over this long a period will have all kinds of quirks in it. For example, the classification scheme the city uses to categorize service requests isn’t static, and for some categories it gets completely redone. At least once over the period the city changed the service provider for data management, which affected measurement in some ways. Meanwhile, on the complaints side, one feature of service databases like this is that some people really like to complain, even by the high standards of New Yorkers. Complaining also becomes easier after the introduction of the web portal, because you can just quickly report something via a form rather than having to make a phone call. So we need to think about how to deal with things like that.
Complaints are ultimately made by individual people, and our dataset is a record of individual reports. But here I’m going to aggregate things to the level of neighborhoods. You can slice up the city in many different ways. New York often uses Neighborhood Tabulation Areas, or NTAs, as its de facto neighborhood unit. The idea is to get something that’s larger than a Census Tract, of which there are about 2,300 in New York, but smaller than one of the City’s 59 Community Districts. There are 262 NTAs, of which 197 are residential. Here’s a map of them, with their names.
So, how can we get from our complaint records to an NTA-level map, and what do we want to see? As I say, here we’re going more or less for data-driven neighborhood trolling, so here’s what I did to characterize each neighborhood. First, I did a fair amount of work harmonizing the complaint categories over the whole dataset, but in addition to that here I’ll just restrict myself to complaints from 2022 to 2025, which is about 13.5m records. Second, we want to moderate the role played by people we can politely call “super-reporters”, so we count distinct addresses within complaint categories, within residential NTAs, over the time period we’re looking at. Each address counts only once in each category it complained about, so we get about 4.6m address-category pairs from about one million unique addresses. (The addresses don’t include identifying information like house or apartment numbers, by the way.) The average address complains in about four or five categories over the four years we’re looking at.
Now, when it comes to complaints, we are all trying to get through this thing we call life and many of the trials we face, we all share. Which is to say that the most common complaints in any given neighborhood are more likely to be the most common complaints in other neighborhoods, too. These are things like the heat and hot water being out, noise of various kinds, and illegal parking. But what we’re interested in is the most distinctive complaints in each neighborhood. So we take every complaint and figure out its share of all complaints citywide. Then we do the same but within each neighborhood. And then for each neighborhood we ask, what category of complaint in this neighborhood most exceeds its citywide share? Actually we do two things. We do that first by general category of complaint, like “Sanitation and Dumping”, or “Parking, Driveways, and Vehicles”, or “Buildings and Construction”. And then we do it for the most fine-grained category we have, like “Traffic: Drag Racing”, or “Appliance: Refrigerator”, or “Lost Property in Taxi or For-Hire Vehicle: Wallet”. Then we color our NTA map in by the broad category and label each neighborhood by its most-specific category. Here’s what that looks like.
I think the results are pretty good. Sorry about the small print and fine detail. This is the sort of thing that works best as a poster. But zoom in and take a look. And of course Tag Yourself. Are you the Badly Behaved Nightlife Crescent from the Upper East Side to Lower Manhattan who got drunk and lost your wallet or keys? (I like how right at the top of the UES they don’t lose their wallets but they do complain about the driver.) Are you the brownstone Brooklyn Bicycle Police? Or the South Brooklyn Curb Cutters who are installing illegal carports? Or maybe you are just out in Woodside, Elmhurst, or Corona, drinking in public. Or abandoning a vehicle somewhere. There’s a lot going on in the city.
Bear in mind that there’s a kind of duality to the map, in the sense that at first glance it shows you what seems to be happening in these NTAs, but only through the lens of what people complain about in these neighborhoods. So, indulge your neighborhood stereotypes, but maybe don’t lean to hard on them. Though I do like those people in Forest Hills who just like to call the cops for unspecified Other Non-Emergency Police Matters. Like, for a chat or something. What else are you gonna do out there on a Friday?
R-bloggers.com offers daily e-mail updates about R news and tutorials about learning R and many other topics. Click here if you're looking to post or find an R/data-science job.
Want to share your content on R-bloggers? click here if you have a blog, or here if you don't.