# Method

## The base

`data/journalists.csv.gz` holds 173,133 classified editorial rows. The published base is
the 127,602 rows with `platform_domain == 0` and `media_typed == 1`: 12,540 rows are
dropped because the vendor stored a link-in-bio, social or freelance-marketplace URL as
the company website, and 32,991 because the outlet's own record does not type it as a
newspaper, broadcaster, online outlet, wire agency or magazine. Every figure here is
computed over all 127,602 rows, not a sample. No row in the base has a blank job title.
The wider classification and the source tables are documented in `data/METHOD.md` in the
repo.

The person rows come from `data.blitz_people`, a read-only Mongo collection, pulled by
`tools/pull_people.py` and `tools/pull_people_new.py` and classified by
`tools/reclassify.py`. The outlet rows come from `data.pdl_company_dataset`, from 125
hand-listed outlets, and from Wikidata. **The person-level base is not published.**
Every file in this dataset is a count per outlet, country, type, role or title string;
no row here names a person, and no headline text appears in any file.

The rows were not fetched in one pull. All 127,602 rows carry a `fetched_at` stamp:

| | |
|---|---|
| earliest | 2026-07-22T08:09:12 |
| median | 2026-08-05T22:04:07 |
| latest | 2026-09-15T10:07:27 |

45,211 rows were fetched in July 2026, 82,383 in August and 8 in September. A count here
is a state of the vendor's records over that window, not a single instant, and someone
promoted inside it can appear under either title.

## Editorial definition

Copied from `data/METHOD.md`, the rule that decides which rows are in the base at all.

A row is editorial when its **title** matches one of: bureau chief, news director,
managing editor, editor-in-chief, sub-editor, correspondent, columnist, anchor,
presenter, news host, newsreader, photojournalist, journalist, reporter, critic,
reviewer, news/newsroom/editorial producer, producer-reporter, staff writer, feature
writer, editor, editorial — **and** its title matches nothing on the stoplist.

Stoplist (applied first, so "marketing editor" and "product editor" are out): sales,
marketing, brand, growth, advertising, ad sales/ops, media buyer, account
manager/executive/director, HR, recruiting, talent, payroll, people ops, engineering,
developer, devops, QA, software, data engineer/scientist/analyst, IT support, product
manager/owner/director/designer/lead, product, content strategist, content marketing,
SEO, copywriter, content writer, technical writer, grant/proposal/ghost/bid writer, PR
and communications roles, finance, accounting, legal counsel, paralegal, facilities,
security guard, driver, customer success/support/service, subscriptions, circulation,
teacher, professor, lecturer, student.

Deliberate exclusions worth knowing about:

- Bare `producer` is **not** editorial. Media companies are full of TV and radio
  production staff; only `news producer`, `newsroom producer`, `editorial producer` and
  `producer / reporter` count.
- Writers count only as `staff writer` and `feature writer`. That drops 10,767 rows
  whose title is bare `writer` or `senior/contributing/lead/freelance/news/sports/
  science/business/political writer`.
- Video, photo, copy and audio editors are kept and tagged in `editor_kind`.

## What a rank word is

One rule: a word is in the lexicon when it puts the holder above or below a plain title.
"Senior reporter" and "assistant editor" carry a rank; "reporter" and "editor" do not.
Words that name a desk, a beat, a medium or a contract (national, digital, freelance,
staff) are not ranks and are out of the lexicon.

**The narrow set is the report's set.** Every count, share, ranking and cut in this
dataset is computed on it. Each word is matched as a whole word over the lowercased job
title:

| word | pattern |
|---|---|
| senior | `\b(senior\|snr\|sr\.?)\b` |
| head of | `\bhead\s+of\b` |
| director | `\bdirector\b` |
| chief | `\b(chief\|editor[\s\-]in[\s\-]chief)\b` |
| deputy | `\bdeputy\b` |
| executive | `\b(executive\|exec)\b` |
| lead | `\blead\b` |
| vp | `\b(vp\|vice\s+president)\b` |
| principal | `\bprincipal\b` |

A wider set adds two words that are a rank only sometimes: bare `head` (`\bhead\b`,
which catches "news head" and "desk head" as well as "head of news") and `managing`
(`\bmanaging\b`). The wide set is carried in the
`wide_rank_count` and `wide_rank_share_pct` columns of every CSV as a second reading.
Nothing is ranked or ordered on it. Over the base the narrow set matches 19,273 titles
(15.1% of 127,602) and the wide set 22,456 (17.6%).

Junior rank words are counted in their own columns and are never part of the rank count
or the language check: `assistant` (or asst), `associate` (or assoc), `junior` (or jr),
`trainee` (or apprentice). `any_rank_count` counts a row once when it carries a narrow
rank word or a junior word: 24,350 rows, 19.1% of the base.

## Matching

The title is lowercased, `&` is read as "and" and whitespace is collapsed, the same
normalisation `data/classify.py` uses. The match runs over the job title alone. The
profile headline, which is user-written, is never read: a headline saying "Senior
journalist and author" does not make the title a senior one. Matching is on whole words,
so "director" matches "Director of News" but not "directorate", and "lead" matches "Lead
Writer" but not "leading".

`title_frequency.csv` lists every distinct job-title string that occurs 5 or more times
in the base with its count and whether it matches the narrow and the wide set, so the
regexes can be checked against real titles without the person-level base. It holds 1,450
strings covering 90,062 of the 127,602 rows, 70.6%.

Three limits of a word match, stated because they set what the number means:

- A rank word in a title is a claim by whoever wrote the profile, not a verified
  position. The file counts the words on the record, not the newsroom's own org chart.
- "Managing editor" is a rank in an English-language newsroom. It is in the wide set
  only, because the same word names a managing director on the business side; rows are
  already restricted to editorial roles by `data/classify.py`, which limits how often
  that happens but does not remove it.
- A title written in a language other than English carries no English rank word, so it
  falls into the non-rank count whatever it says. `bottom20_language_check.csv` measures
  how large that effect is at the bottom of the ranking.

## The outlets

`tools/report_rank_words.py` imports `tools/export.py` and calls its
`load_outlet_records`, `outlet_name`, `outlet_country_code_for`, `fallback_country_code`
and `outlet_type`, so an outlet's name, country and type are the strings the site shows.

Every outlet in the base with 100 or more editorial rows is in scope: 202 outlets
holding 62,302 rows, 48.8% of the base. All 202 carry a publishable name. Eight of them
are parent-company domains rather than single newsrooms (Vox Media, Hearst Magazines,
Pearson, Getty Images, Sky Italia, Paramount, Fox Television Stations, iHeartMedia). The
site's own outlet tables exclude those, and so does the ranking.

**`outlets_ranked_194.csv` is the ranking.** It is the 194 outlets left after the eight
parent-company domains are dropped, holding 58,989 rows, 46.2% of the base, ranked 1 to
194. `outlets_100plus_rank_share.csv` keeps all 202 with a `parent_company_domain`
column, for anyone who wants the parent rows back. Its `rank` column runs 1 to 202 over
that larger set; the two files therefore carry different rank numbers for the same
outlet, and the 194-row file is the one the report quotes.

`rank` is by the exact, unrounded narrow-set share, descending, ties broken by
`editorial_rows`, descending.

One outlet in the 194, Marie Claire, carries country `IT` (Italy) on its record and no
outlet type at all, so it is in the ranking but has no page on the site.

`news18.com` is CNN-News18, an Indian news channel, and table A stores it under a US
country. `names.OUTLET_COUNTRY_OVERRIDES` carries a hand-written ISO code for it, and
`tools/export.py` reads that table first, so the site and this dataset both publish
India. It is the only override in the table.

## The country, type and role cuts

A country row counts the person's own `country_code`, not the outlet's, and appears only
when the country holds 200 rows or more, the cut a country page has to clear on the
site: 43 countries.

A type row counts the rows at outlets `export.py` gives that type. The five named
buckets — newspapers, broadcasters, online, wire agencies, magazines — hold 127,143
rows. The remaining 459 rows sit at outlets `export.py` leaves untyped and are a row of
their own, `(untyped)`, in `rank_share_by_type_and_role.csv`. 127,143 + 459 = 127,602,
the whole base.

A role row counts the `role` column `data/classify.py` assigns.

## The language check

`bottom20_language_check.csv` asks whether the low end of the ranking is a language
effect rather than a newsroom one. It covers the bottom 20 outlets of the 194.

The rule: a title counts when it carries **no rank word from the narrow set** and **none
of the English job nouns editor, reporter, journalist**. No country list is used and no
junior word is used. Every row at those 20 outlets is tested, so the denominator is all
4,663 of them.

- 355 of the 4,663 titles, 7.6%, carry neither a narrow rank word nor an English job
  noun.
- 4,287 of the 4,663 titles, 91.9%, carry the word editor, reporter or journalist.

91.9% of the titles at the bottom twenty are written in English. They are strings like
"Reporter" and "Journalist" with no rank word in front of them. Translation does not
explain the low shares at these outlets.

## Coverage

Coverage differs by outlet and is mostly unknown. A share computed at one outlet is a
share of that outlet's rows on file, not a share of its newsroom.

| outlet | editorial rows on file | published newsroom size | rows on file as a share |
|---|---|---|---|
| Business Insider | 286 | not published | unknown |
| Sveriges Radio | 764 | not published | unknown |
| BBC | 3,935 | 5,500 journalists ([BBC News, Wikipedia](https://en.wikipedia.org/wiki/BBC_News)) | 71.5% |
| The New York Times | 2,168 | 1,700 journalists, 2023 ([The New York Times, Wikipedia](https://en.wikipedia.org/wiki/The_New_York_Times)) | 127.5% |

Both Wikipedia pages were fetched through the Webshare rotating gateway, never from this
machine's IP; `coverage_console.txt` holds the run. The New York Times figure is from
March 2023 and this file is a 2026 snapshot, and our count includes rows the paper would
not count as journalists, which is why it is over 100%. No published headcount was found
for Business Insider or Sveriges Radio, and none was found for the other 190 outlets in
the ranking, so for those the coverage is not known at all.

## Counts under five

A count of 1 to 4 prints "<5" in every CSV and in the console output, so a cell cannot
be read back to a person. Shares are computed from the true counts before the mask is
applied.

## The sanity check

Fetched through the Webshare rotating gateway, never from this machine's IP;
`sanity_console.txt` holds the run with the status codes.

Indeed Hiring Lab, 2026-07-23, HTTP 200: "only about 14% of postings are for senior
positions nationwide, while entry- and mid-level postings represent 46% and 40%". Ours
is 15.1% of newsroom job titles carrying one of the ten narrow-set rank words. The two
numbers are close, but they measure different things over different populations: Indeed
classifies US job postings across the whole labour market by its own seniority model,
and this file matches ten words over newsroom job titles on profile records. It is a
scale check on 15.1%, not a comparison.

The Global Times report of LinkedIn's 2005 to 2009 title growth (HTTP 200) is a growth
rate, not a share, and is not compared with anything here. The Economist's 2022 piece on
title inflation returned HTTP 500 through the proxy and BBC Worklife's returned 404, so
neither was read.

No public source was found that gives the share of job titles containing a specific rank
word, so 15.1% has no direct outside comparison.

## Licence

CC BY 4.0. Cite as JournalistLabs, "Rank words in newsroom job titles", 2026-09-16, rows
collected 2026-07-22 to 2026-09-15.
