Democase Diagnosehäufigkeiten
Harald G. Grohganz, Visionsberatung GmbH, 24.01.2025
Eine 1%-Stichprobe der Diagnosen aller gesetzlich Versicherten in Deutschland in den Jahren 2012 und 2017 – erstellt mithilfe des Public Use File des Forschungsdatenzentrum Gesundheit am Bundesinstitut für Arzneimittel und Medizinprodukte (BfArM).
Das Public Use File ist stark anonymisiert. Alle Spalten wurden separat zufällig permutiert, daher können echte Informationen nur durch Betrachtung einer Einzelspalte gewonnen werden. Wir lesen also pro Datei auch nur eine Spalte ein. Dadurch können wir nur die Diagnosehäufigkeiten auslesen – wir können nicht unterscheiden, ob eine Person eine Diagnose mehrfach bekommen hat oder ob es mehrere Personen waren.
Quellen
- Public Use File:
https://zenodo.org/records/14524120
- Datensatzbeschreibung:
https://fdz-gesundheit.github.io/datensatzbeschreibung_fdz_gesundheit/
- ICD-Kataloge für 2012 und 2017:
https://www.bfarm.de/SharedDocs/Downloads/DE/Kodiersysteme/klassifikationen/icd-10-gm/vorgaenger-bis-2020/icd10gm2012_zip.html
https://www.bfarm.de/SharedDocs/Downloads/DE/Kodiersysteme/klassifikationen/icd-10-gm/vorgaenger-bis-2020/icd10gm2017_zip.html
Vorbereitungen
- CSV-Dateien des PUF herunterladen und entzippen.
- Lektüre der Datensatzbeschreibung, um die Struktur der Daten nachzuvollziehen.
- ICD-Kataloge herunterladen. Das sind sehr umfangreiche ZIP-Archive, uns interessieren nur die txt/csv-Dateien aus dem jew. Ordner beginnend mit
x1gm
(Metadaten zur ICD im csv-Format). Dort die drei txt-Dateien zu Kodes, Gruppen und Kapiteln entpacken.
import pandas as pd
Einlesen der Daten
# Wir brauchen aus der CSV nur die Spalte mit den ICD-Codes
# Daran spielen wir die Infos aus den Metadaten: Jahr & Typ (d.h. stationär oder ambulant)
def read_diagnoses(dm, sa):
df_tmp = pd.read_csv(dm+"/"+sa+".csv", usecols=[sa+"_ICD_CODE"], dtype=str)
df_tmp.columns = ["ICD"]
df_tmp["Jahr"] = "2012" if dm == "DM1" else "2017"
df_tmp["Typ"] = "stationär" if sa == "SA551" else "ambulant"
return df_tmp
# Nun lesen wir die einzelnen Rohdatendateien ein und hängen sie in eine große Tabelle untereinander
df = pd.concat([
read_diagnoses("DM1", "SA551"),
read_diagnoses("DM2", "SA551"),
read_diagnoses("DM1", "SA651"),
read_diagnoses("DM2", "SA651")
])
# Um die Dateigröße webtauglich (klein) zu halten, nutzen wir später nur die ersten 3 Stellen der ICD-Codes
df["ICD3"] = df["ICD"].str[0:3]
# Ein erster Blick...
df
ICD | Jahr | Typ | ICD3 | |
---|---|---|---|---|
0 | Z922 | 2012 | stationär | Z92 |
1 | G431 | 2012 | stationär | G43 |
2 | Z867 | 2012 | stationär | Z86 |
3 | I200 | 2012 | stationär | I20 |
4 | C4131 | 2012 | stationär | C41 |
... | ... | ... | ... | ... |
24335376 | K219 | 2017 | ambulant | K21 |
24335377 | E6699 | 2017 | ambulant | E66 |
24335378 | K529 | 2017 | ambulant | K52 |
24335379 | H520 | 2017 | ambulant | H52 |
24335380 | R103 | 2017 | ambulant | R10 |
45017329 rows × 4 columns
Zusammenfassen der Daten
# Daten zusammenfassen - von 45 Mio auf 6500
df_grp = df.groupby(["Typ", "Jahr", "ICD3"]).size().reset_index(name='Anzahl')
df_grp
Typ | Jahr | ICD3 | Anzahl | |
---|---|---|---|---|
0 | ambulant | 2012 | 999 | 6 |
1 | ambulant | 2012 | A00 | 43 |
2 | ambulant | 2012 | A01 | 178 |
3 | ambulant | 2012 | A02 | 1031 |
4 | ambulant | 2012 | A03 | 78 |
... | ... | ... | ... | ... |
6584 | stationär | 2017 | Z95 | 21133 |
6585 | stationär | 2017 | Z96 | 8055 |
6586 | stationär | 2017 | Z97 | 1246 |
6587 | stationär | 2017 | Z98 | 2672 |
6588 | stationär | 2017 | Z99 | 3827 |
6589 rows × 4 columns
Die ICD-Informationen
def read_icd(files):
icd_kodes = pd.read_csv(r"ICD/"+files[0]+".txt", sep=";", dtype=str, header=None)
icd_grp = pd.read_csv(r"ICD/"+files[1]+".txt", sep=";", dtype=str, header=None)
icd_kap = pd.read_csv(r"ICD/"+files[2]+".txt", sep=";", dtype=str, header=None)
icd_grp["Gruppe"] = icd_grp[0] + "-" + icd_grp[1]
icd = pd.merge(pd.merge(icd_kodes[[3,4,7,8]],
icd_grp[[0,3,"Gruppe"]],
how="left", left_on=4, right_on=0),
icd_kap,
how="left", left_on="3_x", right_on=0)
icd = icd[[7, 8, "Gruppe", "3_y", "3_x", 1]]
icd.columns = ["ICD3", "ICD3_Name", "ICD2", "ICD2_Name", "ICD1", "ICD1_Name"]
return icd[icd["ICD3"].str.len() == 3]
icd_files_2017 = ["icd10gm2017syst_kodes", "icd10gm2017syst_gruppen", "icd10gm2017syst_kapitel"]
icd_files_2012 = ["icd10gmsyst_kodes2012", "icd10gmsyst_gruppen2012", "icd10gmsyst_kapitel2012"]
icd_2012 = read_icd(icd_files_2012)
icd_2017 = read_icd(icd_files_2017)
icd_2012["ICD_Jahr"] = "2012"
icd_2017["ICD_Jahr"] = "2017"
df_icd = pd.concat([icd_2012, icd_2017])
df_icd
ICD3 | ICD3_Name | ICD2 | ICD2_Name | ICD1 | ICD1_Name | ICD_Jahr | |
---|---|---|---|---|---|---|---|
0 | A00 | Cholera | A00-A09 | Infektiöse Darmkrankheiten | 01 | Bestimmte infektiöse und parasitäre Krankheiten | 2012 |
4 | A01 | Typhus abdominalis und Paratyphus | A00-A09 | Infektiöse Darmkrankheiten | 01 | Bestimmte infektiöse und parasitäre Krankheiten | 2012 |
10 | A02 | Sonstige Salmonelleninfektionen | A00-A09 | Infektiöse Darmkrankheiten | 01 | Bestimmte infektiöse und parasitäre Krankheiten | 2012 |
16 | A03 | Shigellose [Bakterielle Ruhr] | A00-A09 | Infektiöse Darmkrankheiten | 01 | Bestimmte infektiöse und parasitäre Krankheiten | 2012 |
23 | A04 | Sonstige bakterielle Darminfektionen | A00-A09 | Infektiöse Darmkrankheiten | 01 | Bestimmte infektiöse und parasitäre Krankheiten | 2012 |
... | ... | ... | ... | ... | ... | ... | ... |
15912 | U82 | Mykobakterien mit Resistenz gegen Antituberkul... | U80-U85 | Infektionserreger mit Resistenzen gegen bestim... | 22 | Schlüsselnummern für besondere Zwecke | 2017 |
15916 | U83 | Candida mit Resistenz gegen Fluconazol oder Vo... | U80-U85 | Infektionserreger mit Resistenzen gegen bestim... | 22 | Schlüsselnummern für besondere Zwecke | 2017 |
15917 | U84 | Herpesviren mit Resistenz gegen Virustatika | U80-U85 | Infektionserreger mit Resistenzen gegen bestim... | 22 | Schlüsselnummern für besondere Zwecke | 2017 |
15918 | U85 | Humanes Immundefizienz-Virus mit Resistenz geg... | U80-U85 | Infektionserreger mit Resistenzen gegen bestim... | 22 | Schlüsselnummern für besondere Zwecke | 2017 |
15919 | U99 | Nicht belegte Schlüsselnummer U99 | U99-U99 | Nicht belegte Schlüsselnummern | 22 | Schlüsselnummern für besondere Zwecke | 2017 |
3420 rows × 7 columns
Abschluss: Daten mit ICD-Hierarchie anreichern
df_final = df_grp.merge(df_icd, left_on=["ICD3","Jahr"], right_on=["ICD3", "ICD_Jahr"], how="left")
df_final
Typ | Jahr | ICD3 | Anzahl | ICD3_Name | ICD2 | ICD2_Name | ICD1 | ICD1_Name | ICD_Jahr | |
---|---|---|---|---|---|---|---|---|---|---|
0 | ambulant | 2012 | 999 | 6 | NaN | NaN | NaN | NaN | NaN | NaN |
1 | ambulant | 2012 | A00 | 43 | Cholera | A00-A09 | Infektiöse Darmkrankheiten | 01 | Bestimmte infektiöse und parasitäre Krankheiten | 2012 |
2 | ambulant | 2012 | A01 | 178 | Typhus abdominalis und Paratyphus | A00-A09 | Infektiöse Darmkrankheiten | 01 | Bestimmte infektiöse und parasitäre Krankheiten | 2012 |
3 | ambulant | 2012 | A02 | 1031 | Sonstige Salmonelleninfektionen | A00-A09 | Infektiöse Darmkrankheiten | 01 | Bestimmte infektiöse und parasitäre Krankheiten | 2012 |
4 | ambulant | 2012 | A03 | 78 | Shigellose [Bakterielle Ruhr] | A00-A09 | Infektiöse Darmkrankheiten | 01 | Bestimmte infektiöse und parasitäre Krankheiten | 2012 |
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
6584 | stationär | 2017 | Z95 | 21133 | Vorhandensein von kardialen oder vaskulären Im... | Z80-Z99 | Personen mit potentiellen Gesundheitsrisiken a... | 21 | Faktoren, die den Gesundheitszustand beeinflus... | 2017 |
6585 | stationär | 2017 | Z96 | 8055 | Vorhandensein von anderen funktionellen Implan... | Z80-Z99 | Personen mit potentiellen Gesundheitsrisiken a... | 21 | Faktoren, die den Gesundheitszustand beeinflus... | 2017 |
6586 | stationär | 2017 | Z97 | 1246 | Vorhandensein anderer medizinischer Geräte ode... | Z80-Z99 | Personen mit potentiellen Gesundheitsrisiken a... | 21 | Faktoren, die den Gesundheitszustand beeinflus... | 2017 |
6587 | stationär | 2017 | Z98 | 2672 | Sonstige Zustände nach chirurgischem Eingriff | Z80-Z99 | Personen mit potentiellen Gesundheitsrisiken a... | 21 | Faktoren, die den Gesundheitszustand beeinflus... | 2017 |
6588 | stationär | 2017 | Z99 | 3827 | Abhängigkeit (langzeitig) von unterstützenden ... | Z80-Z99 | Personen mit potentiellen Gesundheitsrisiken a... | 21 | Faktoren, die den Gesundheitszustand beeinflus... | 2017 |
6589 rows × 10 columns
# Spalten umsortieren und abspeichern
df_final = df_final[["ICD1", "ICD1_Name", "ICD2", "ICD2_Name", "ICD3", "ICD3_Name", "Typ", "Jahr", "Anzahl"]]
df_final.to_csv("diagnosen_PUF.csv", index=False, encoding='utf8')