N9: fixed-2010 cohort series and windowed-key (k = 3, 5) first-seen series for Table 14 / Figure 5
Items: FIRC0001-ADVE-13 ADVE-14 ECON-14 THEO-15. 2011-2025 first-seen range 6,240-8,216 (all issuers; 2010 = 7,835 left-censored, 2026 partial); fixed cohort of 1,389 issuers: new projects per issuer 4.7 (2011) -> 2.8 (2025) while mentions per issuer stay 9.6 -> 8.8; k = 3 / 5 episodes 131,823 / 126,318 vs 121,099. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
5 changed files +202 −0
added
code/audit/a09_timeseries_cohort.py
+47 −0
@@ -0,0 +1,47 @@ | |||||
| 1 | +"""N9 - fixed-2010 cohort series and windowed-key first-seen series for Table 14 / Figure 5 (cluster K). Read-only.""" | ||||
| 2 | +from __future__ import annotations | ||||
| 3 | +import sys | ||||
| 4 | +from pathlib import Path | ||||
| 5 | +sys.path.insert(0, str(Path(__file__).resolve().parent)) | ||||
| 6 | +from common import * | ||||
| 7 | + | ||||
| 8 | +r = Run("timeseries") | ||||
| 9 | +con = connect(SPID_DB) | ||||
| 10 | +con.execute("""CREATE TEMP TABLE fy AS SELECT cik, year(filing_date) yr, count(*) n FROM src_filings GROUP BY 1,2""") | ||||
| 11 | +con.execute("""CREATE TEMP TABLE cohort AS SELECT cik FROM fy WHERE yr BETWEEN 2010 AND 2025 GROUP BY 1 HAVING count(DISTINCT yr) = 16""") | ||||
| 12 | +S = {"cohort_issuers": con.execute("select count(*) from cohort").fetchone()[0], "all_issuers_with_filings": con.execute("select count(distinct cik) from src_filings").fetchone()[0], | ||||
| 13 | + "max_filing_date": str(con.execute("select max(filing_date) from src_filings").fetchone()[0]), "min_filing_date": str(con.execute("select min(filing_date) from src_filings").fetchone()[0]), | ||||
| 14 | + "note": "2010 is left-censored (first_seen cannot precede the corpus start); 2026 is partial (filings to the max date)"} | ||||
| 15 | +con.execute("""CREATE TEMP TABLE _k AS SELECT m.*, lower(coalesce(try(locations[1]), '')) AS loc1, | ||||
| 16 | + regexp_extract(lower(regexp_replace(project_name, '[^A-Za-z ]', '', 'g')), '([a-z]{4,})', 1) AS name_tok FROM project_mentions m""") | ||||
| 17 | +con.execute("""CREATE TEMP TABLE k AS SELECT *, cik || '|' || project_type || '|' || CASE WHEN loc1 <> '' THEN loc1 ELSE coalesce(nullif(name_tok,''),'general') END AS gkey FROM _k""") | ||||
| 18 | +# windowed key: a new episode starts when the gap to the previous mention of the same gkey exceeds kk years | ||||
| 19 | +con.execute("""CREATE TEMP TABLE ep AS SELECT gkey, cik, filing_date, | ||||
| 20 | + lag(filing_date) OVER (PARTITION BY gkey ORDER BY filing_date, mention_id) prev FROM k""") | ||||
| 21 | +def series(where_cohort: str, label: str): | ||||
| 22 | + return con.execute(f""" | ||||
| 23 | + WITH yrs AS (SELECT unnest(generate_series(2010, 2026)) yr), | ||||
| 24 | + iss AS (SELECT yr, count(DISTINCT cik) issuers_filing FROM fy WHERE {where_cohort.replace('k.cik','fy.cik')} GROUP BY 1), | ||||
| 25 | + men AS (SELECT year(filing_date) yr, count(*) mentions, count(DISTINCT cik) issuers_with_mentions FROM k WHERE {where_cohort} GROUP BY 1), | ||||
| 26 | + fs AS (SELECT year(min(filing_date)) yr, gkey FROM k WHERE {where_cohort} GROUP BY gkey), | ||||
| 27 | + fsy AS (SELECT yr, count(*) first_seen_current FROM fs GROUP BY 1), | ||||
| 28 | + e3 AS (SELECT year(filing_date) yr, count(*) first_seen_k3 FROM ep e WHERE (prev IS NULL OR filing_date - prev > 3*365) AND {where_cohort.replace('k.cik','e.cik')} GROUP BY 1), | ||||
| 29 | + e5 AS (SELECT year(filing_date) yr, count(*) first_seen_k5 FROM ep e WHERE (prev IS NULL OR filing_date - prev > 5*365) AND {where_cohort.replace('k.cik','e.cik')} GROUP BY 1) | ||||
| 30 | + SELECT '{label}' series, yrs.yr, coalesce(iss.issuers_filing,0) issuers_filing, coalesce(men.mentions,0) mentions, coalesce(men.issuers_with_mentions,0) issuers_with_mentions, | ||||
| 31 | + round(coalesce(men.mentions,0)*1.0/nullif(iss.issuers_filing,0),2) mentions_per_issuer_filing, | ||||
| 32 | + coalesce(fsy.first_seen_current,0) first_seen_current_key, round(coalesce(fsy.first_seen_current,0)*1.0/nullif(iss.issuers_filing,0),2) first_seen_per_issuer, | ||||
| 33 | + coalesce(e3.first_seen_k3,0) first_seen_k3, coalesce(e5.first_seen_k5,0) first_seen_k5, | ||||
| 34 | + CASE WHEN yrs.yr = 2010 THEN 'left-censored' WHEN yrs.yr = 2026 THEN 'partial year' ELSE '' END flag | ||||
| 35 | + FROM yrs LEFT JOIN iss USING (yr) LEFT JOIN men USING (yr) LEFT JOIN fsy USING (yr) LEFT JOIN e3 USING (yr) LEFT JOIN e5 USING (yr) ORDER BY 2""").fetchall() | ||||
| 36 | +cols = ["series","year","issuers_filing","mentions","issuers_with_mentions","mentions_per_issuer_filing","first_seen_current_key","first_seen_per_issuer","first_seen_k3","first_seen_k5","flag"] | ||||
| 37 | +allr = series("TRUE", "all_issuers"); coh = series("k.cik IN (SELECT cik FROM cohort)", "fixed_2010_cohort") | ||||
| 38 | +r.write_csv("first_seen_fixed_cohort.csv", cols, allr + coh) | ||||
| 39 | +r.write_csv("windowed_key_k3_k5.csv", ["series","year","first_seen_current_key","first_seen_k3","first_seen_k5","flag"], [(x[0], x[1], x[6], x[8], x[9], x[10]) for x in allr + coh]) | ||||
| 40 | +S["range_2011_2025_first_seen_all"] = [min(x[6] for x in allr if 2011 <= x[1] <= 2025), max(x[6] for x in allr if 2011 <= x[1] <= 2025)] | ||||
| 41 | +S["range_2011_2025_first_seen_cohort"] = [min(x[6] for x in coh if 2011 <= x[1] <= 2025), max(x[6] for x in coh if 2011 <= x[1] <= 2025)] | ||||
| 42 | +S["first_seen_2010_all"] = [x[6] for x in allr if x[1] == 2010][0] | ||||
| 43 | +S["mentions_per_issuer_cohort_2011_vs_2025"] = [[x[1], x[5]] for x in coh if x[1] in (2011, 2015, 2020, 2025)] | ||||
| 44 | +S["first_seen_per_issuer_cohort_2011_vs_2025"] = [[x[1], x[7]] for x in coh if x[1] in (2011, 2015, 2020, 2025)] | ||||
| 45 | +S["episodes_k3_total"], S["episodes_k5_total"], S["projects_current"] = con.execute("select count(*) filter (where prev is null or filing_date - prev > 3*365), count(*) filter (where prev is null or filing_date - prev > 5*365), count(distinct gkey) from ep").fetchone() | ||||
| 46 | +r.write_json("summary.json", S) | ||||
| 47 | +r.finish() | ||||
added
results/timeseries/first_seen_fixed_cohort.csv
+35 −0
@@ -0,0 +1,35 @@ | |||||
| 1 | +series,year,issuers_filing,mentions,issuers_with_mentions,mentions_per_issuer_filing,first_seen_current_key,first_seen_per_issuer,first_seen_k3,first_seen_k5,flag | ||||
| 2 | +all_issuers,2010,1392,11908,1224,8.55,7835,5.63,7835,7835,left-censored | ||||
| 3 | +all_issuers,2011,1424,13551,1287,9.52,6679,4.69,6679,6679, | ||||
| 4 | +all_issuers,2012,1472,14302,1333,9.72,6444,4.38,6444,6444, | ||||
| 5 | +all_issuers,2013,1539,14611,1408,9.49,6286,4.08,6385,6286, | ||||
| 6 | +all_issuers,2014,1619,16274,1490,10.05,6732,4.16,7004,6732, | ||||
| 7 | +all_issuers,2015,1689,17073,1535,10.11,6675,3.95,7092,6734, | ||||
| 8 | +all_issuers,2016,1744,16429,1579,9.42,6240,3.58,6710,6372, | ||||
| 9 | +all_issuers,2017,1810,17350,1636,9.59,6490,3.59,7120,6725, | ||||
| 10 | +all_issuers,2018,1893,18064,1737,9.54,6815,3.6,7529,7115, | ||||
| 11 | +all_issuers,2019,1973,18737,1806,9.5,6837,3.47,7644,7208, | ||||
| 12 | +all_issuers,2020,2089,17970,1919,8.6,7212,3.45,8010,7649, | ||||
| 13 | +all_issuers,2021,2247,21312,2077,9.48,8216,3.66,9191,8732, | ||||
| 14 | +all_issuers,2022,2291,22720,2105,9.92,8158,3.56,9135,8689, | ||||
| 15 | +all_issuers,2023,2329,22955,2129,9.86,7977,3.43,9061,8557, | ||||
| 16 | +all_issuers,2024,2387,22503,2204,9.43,7819,3.28,8954,8500, | ||||
| 17 | +all_issuers,2025,2453,23220,2280,9.47,7990,3.26,9252,8719, | ||||
| 18 | +all_issuers,2026,2498,19086,2260,7.64,6694,2.68,7778,7342,partial year | ||||
| 19 | +fixed_2010_cohort,2010,1389,11889,1221,8.56,7819,5.63,7819,7819,left-censored | ||||
| 20 | +fixed_2010_cohort,2011,1389,13333,1255,9.6,6533,4.7,6533,6533, | ||||
| 21 | +fixed_2010_cohort,2012,1389,13775,1262,9.92,6125,4.41,6125,6125, | ||||
| 22 | +fixed_2010_cohort,2013,1389,13411,1276,9.66,5602,4.03,5701,5602, | ||||
| 23 | +fixed_2010_cohort,2014,1389,13999,1285,10.08,5583,4.02,5852,5583, | ||||
| 24 | +fixed_2010_cohort,2015,1389,14038,1270,10.11,5288,3.81,5700,5347, | ||||
| 25 | +fixed_2010_cohort,2016,1389,13093,1275,9.43,4810,3.46,5260,4941, | ||||
| 26 | +fixed_2010_cohort,2017,1389,13088,1258,9.42,4674,3.37,5274,4907, | ||||
| 27 | +fixed_2010_cohort,2018,1389,13035,1271,9.38,4719,3.4,5373,5009, | ||||
| 28 | +fixed_2010_cohort,2019,1389,12937,1277,9.31,4496,3.24,5235,4852, | ||||
| 29 | +fixed_2010_cohort,2020,1389,11371,1294,8.19,4380,3.15,5069,4779, | ||||
| 30 | +fixed_2010_cohort,2021,1389,12376,1284,8.91,4505,3.24,5327,4972, | ||||
| 31 | +fixed_2010_cohort,2022,1389,12870,1273,9.27,4447,3.2,5224,4902, | ||||
| 32 | +fixed_2010_cohort,2023,1389,12649,1254,9.11,4251,3.06,5098,4752, | ||||
| 33 | +fixed_2010_cohort,2024,1389,12170,1277,8.76,4085,2.94,4953,4663, | ||||
| 34 | +fixed_2010_cohort,2025,1389,12156,1285,8.75,3926,2.83,4858,4518, | ||||
| 35 | +fixed_2010_cohort,2026,1389,9792,1244,7.05,3192,2.3,3958,3697,partial year | ||||
added
results/timeseries/manifest.json
+30 −0
@@ -0,0 +1,30 @@ | |||||
| 1 | +{ | ||||
| 2 | + "package": "timeseries", | ||||
| 3 | + "script": "/Users/simon-pierreboucher/firc0001_review/scripts/a09_timeseries_cohort.py", | ||||
| 4 | + "script_sha256": "e8220e405587cc0c1f4ea1ae3750d85fe8f5240ab0f464444351f41988f05083", | ||||
| 5 | + "started": "2026-11-05T14:29:36", | ||||
| 6 | + "ended": "2026-11-05T14:29:36", | ||||
| 7 | + "wall_seconds": 0.4, | ||||
| 8 | + "node": "m3u96b", | ||||
| 9 | + "python": "3.12.15", | ||||
| 10 | + "duckdb": "2.0.0", | ||||
| 11 | + "threads": 4, | ||||
| 12 | + "memory_limit": "24GB", | ||||
| 13 | + "seed": 20261105, | ||||
| 14 | + "databases": { | ||||
| 15 | + "/Users/simon-pierreboucher/UQO_RESEARCH_DB/project-db/data/db/spid.duckdb": { | ||||
| 16 | + "bytes": 3155701760, | ||||
| 17 | + "mtime": "2026-10-28T12:21:11.091389" | ||||
| 18 | + }, | ||||
| 19 | + "/Users/simon-pierreboucher/UQO_RESEARCH_DB/data/duckdb/edgar_research.duckdb": { | ||||
| 20 | + "bytes": 73500995584, | ||||
| 21 | + "mtime": "2026-10-27T21:34:46.297884" | ||||
| 22 | + } | ||||
| 23 | + }, | ||||
| 24 | + "read_only": true, | ||||
| 25 | + "row_counts": { | ||||
| 26 | + "first_seen_fixed_cohort.csv": 34, | ||||
| 27 | + "windowed_key_k3_k5.csv": 34 | ||||
| 28 | + }, | ||||
| 29 | + "notes": {} | ||||
| 30 | +} | ||||
| \ No newline at end of file | |||||
added
results/timeseries/summary.json
+55 −0
@@ -0,0 +1,55 @@ | |||||
| 1 | +{ | ||||
| 2 | + "cohort_issuers": 1389, | ||||
| 3 | + "all_issuers_with_filings": 2499, | ||||
| 4 | + "max_filing_date": "2026-10-27", | ||||
| 5 | + "min_filing_date": "2010-01-04", | ||||
| 6 | + "note": "2010 is left-censored (first_seen cannot precede the corpus start); 2026 is partial (filings to the max date)", | ||||
| 7 | + "range_2011_2025_first_seen_all": [ | ||||
| 8 | + 6240, | ||||
| 9 | + 8216 | ||||
| 10 | + ], | ||||
| 11 | + "range_2011_2025_first_seen_cohort": [ | ||||
| 12 | + 3926, | ||||
| 13 | + 6533 | ||||
| 14 | + ], | ||||
| 15 | + "first_seen_2010_all": 7835, | ||||
| 16 | + "mentions_per_issuer_cohort_2011_vs_2025": [ | ||||
| 17 | + [ | ||||
| 18 | + 2011, | ||||
| 19 | + 9.6 | ||||
| 20 | + ], | ||||
| 21 | + [ | ||||
| 22 | + 2015, | ||||
| 23 | + 10.11 | ||||
| 24 | + ], | ||||
| 25 | + [ | ||||
| 26 | + 2020, | ||||
| 27 | + 8.19 | ||||
| 28 | + ], | ||||
| 29 | + [ | ||||
| 30 | + 2025, | ||||
| 31 | + 8.75 | ||||
| 32 | + ] | ||||
| 33 | + ], | ||||
| 34 | + "first_seen_per_issuer_cohort_2011_vs_2025": [ | ||||
| 35 | + [ | ||||
| 36 | + 2011, | ||||
| 37 | + 4.7 | ||||
| 38 | + ], | ||||
| 39 | + [ | ||||
| 40 | + 2015, | ||||
| 41 | + 3.81 | ||||
| 42 | + ], | ||||
| 43 | + [ | ||||
| 44 | + 2020, | ||||
| 45 | + 3.15 | ||||
| 46 | + ], | ||||
| 47 | + [ | ||||
| 48 | + 2025, | ||||
| 49 | + 2.83 | ||||
| 50 | + ] | ||||
| 51 | + ], | ||||
| 52 | + "episodes_k3_total": 131823, | ||||
| 53 | + "episodes_k5_total": 126318, | ||||
| 54 | + "projects_current": 121099 | ||||
| 55 | +} | ||||
| \ No newline at end of file | |||||
added
results/timeseries/windowed_key_k3_k5.csv
+35 −0
@@ -0,0 +1,35 @@ | |||||
| 1 | +series,year,first_seen_current_key,first_seen_k3,first_seen_k5,flag | ||||
| 2 | +all_issuers,2010,7835,7835,7835,left-censored | ||||
| 3 | +all_issuers,2011,6679,6679,6679, | ||||
| 4 | +all_issuers,2012,6444,6444,6444, | ||||
| 5 | +all_issuers,2013,6286,6385,6286, | ||||
| 6 | +all_issuers,2014,6732,7004,6732, | ||||
| 7 | +all_issuers,2015,6675,7092,6734, | ||||
| 8 | +all_issuers,2016,6240,6710,6372, | ||||
| 9 | +all_issuers,2017,6490,7120,6725, | ||||
| 10 | +all_issuers,2018,6815,7529,7115, | ||||
| 11 | +all_issuers,2019,6837,7644,7208, | ||||
| 12 | +all_issuers,2020,7212,8010,7649, | ||||
| 13 | +all_issuers,2021,8216,9191,8732, | ||||
| 14 | +all_issuers,2022,8158,9135,8689, | ||||
| 15 | +all_issuers,2023,7977,9061,8557, | ||||
| 16 | +all_issuers,2024,7819,8954,8500, | ||||
| 17 | +all_issuers,2025,7990,9252,8719, | ||||
| 18 | +all_issuers,2026,6694,7778,7342,partial year | ||||
| 19 | +fixed_2010_cohort,2010,7819,7819,7819,left-censored | ||||
| 20 | +fixed_2010_cohort,2011,6533,6533,6533, | ||||
| 21 | +fixed_2010_cohort,2012,6125,6125,6125, | ||||
| 22 | +fixed_2010_cohort,2013,5602,5701,5602, | ||||
| 23 | +fixed_2010_cohort,2014,5583,5852,5583, | ||||
| 24 | +fixed_2010_cohort,2015,5288,5700,5347, | ||||
| 25 | +fixed_2010_cohort,2016,4810,5260,4941, | ||||
| 26 | +fixed_2010_cohort,2017,4674,5274,4907, | ||||
| 27 | +fixed_2010_cohort,2018,4719,5373,5009, | ||||
| 28 | +fixed_2010_cohort,2019,4496,5235,4852, | ||||
| 29 | +fixed_2010_cohort,2020,4380,5069,4779, | ||||
| 30 | +fixed_2010_cohort,2021,4505,5327,4972, | ||||
| 31 | +fixed_2010_cohort,2022,4447,5224,4902, | ||||
| 32 | +fixed_2010_cohort,2023,4251,5098,4752, | ||||
| 33 | +fixed_2010_cohort,2024,4085,4953,4663, | ||||
| 34 | +fixed_2010_cohort,2025,3926,4858,4518, | ||||
| 35 | +fixed_2010_cohort,2026,3192,3958,3697,partial year | ||||
| 36 | |||||