saxoforn

SaxoForN data extraction tool
git clone git://arztpraxis-lohmann.de/saxoforn
Log | Files | Refs | LICENSE

saxofornQ42023.py (10505B)


      1 #!/usr/bin/env python
      2 # coding=utf-8
      3 #
      4 # © 2019-2024 Christoph Lohmann <20h@r-36.net>
      5 #
      6 # This file is published under the terms of the GPLv3.
      7 #
      8 
      9 import os
     10 import sys
     11 import getopt
     12 import codecs
     13 from datetime import datetime
     14 import operator
     15 
     16 topicno = 1
     17 
     18 # Return num of patients who have one occurence of some ebmcodes.
     19 def ebmcodeoccurence(container, ebmcodes):
     20 	occurence = 0
     21 	for sentence in container["sentences"]:
     22 		found = 0
     23 		for field in sentence["fields"]:
     24 			if field[0] == 5001:
     25 				if field[1] in ebmcodes:
     26 					if found == 0:
     27 						occurence += 1
     28 					found = 1
     29 	return occurence
     30 
     31 # Return sum of all occurences of some ebmcodes.
     32 def ebmcodesumoccurence(container, ebmcodes):
     33 	occurence = 0
     34 	for sentence in container["sentences"]:
     35 		for field in sentence["fields"]:
     36 			if field[0] == 5001:
     37 				if field[1] in ebmcodes:
     38 					occurence += 1
     39 	return occurence
     40 
     41 def expandcodes(codes):
     42 	newcodes = []
     43 	for code in codes:
     44 		if code.endswith(".-"):
     45 			for c in "012345678":
     46 				newcodes.append(code.replace("-", c))
     47 		else:
     48 			newcodes.append(code)
     49 	return newcodes
     50 
     51 def printcode(codesdb, code):
     52 	if code in codesdb:
     53 		print("%s = %d" % (code, codesdb[code]))
     54 	else:
     55 		print("%s = 0" % (code))
     56 
     57 def printcodes(codesdb, codes):
     58 	newcodes = expandcodes(codes)
     59 	for code in newcodes:
     60 		printcode(codesdb, code)
     61 
     62 def printcodessum(codesdb, codes):
     63 	codesum = 0
     64 	newcodes = expandcodes(codes)
     65 	for code in newcodes:
     66 		if code in codesdb:
     67 			codesum += codesdb[code]
     68 	print("%s = %d" % (newcodes, codesum))
     69 
     70 def sentence2dict(sentence):
     71 	rdict = {}
     72 
     73 	if not "fields" in sentence:
     74 		return rdict
     75 
     76 	for field in sentence["fields"]:
     77 		fstr = "%s" % (field[0])
     78 		if not fstr in rdict:
     79 			rdict[fstr] = []
     80 		rdict[fstr].append(field[1])
     81 
     82 	return rdict
     83 
     84 def parse_xdt(line):
     85 	length = int(line[:3])
     86 	fieldid = int(line[3:7])
     87 	fcontent = line[7:-2]
     88 
     89 	if length != len(line):
     90 		print("Invalid line: %s\n" % (line[:-2]))
     91 
     92 	return (length, fieldid, fcontent)
     93 
     94 def usage(app):
     95 	app = os.path.basename(app)
     96 	print("usage: %s [-h] adt.con" % (app), file=sys.stderr)
     97 	sys.exit(1)
     98 
     99 def main(args):
    100 	try:
    101 		opts, largs = getopt.getopt(args[1:], "h")
    102 	except getopt.GetoptError as err:
    103 		print(str(err))
    104 		usage(args[0])
    105 	
    106 	for o, a in opts:
    107 		if o == "-h":
    108 			usage(args[0])
    109 		else:
    110 			assert False, "unhandled option"
    111 
    112 	if len(largs) < 1:
    113 		usage(args[0])
    114 
    115 	# Aerzte
    116 	besa = {}
    117 	# Betriebsstaette
    118 	rvsa = {}
    119 	# PVS-Hersteller
    120 	adt0 = {}
    121 
    122 	begin = datetime.now()
    123 	lines = 0
    124 	containers = []
    125 	container = {}
    126 	sentence = {}
    127 	with codecs.open(largs[0], "r", "iso8859-15") as fd:
    128 		for line in fd:
    129 			(length, fieldid, fcontent) = parse_xdt(line)
    130 			lines += 1
    131 
    132 			#print((length, fieldid, fcontent))
    133 			if fieldid == 8000:
    134 				if fcontent == "con0":
    135 					container["name"] = fcontent
    136 					container["sentences"] = []
    137 					container["fields"] = []
    138 				elif fcontent == "con9":
    139 					if sentence != {}:
    140 						container["sentences"].append(sentence)
    141 					containers.append(container)
    142 					container = {}
    143 					sentence = {}
    144 				elif fcontent == "adt9":
    145 					if sentence != {}:
    146 						container["sentences"].append(sentence)
    147 					continue
    148 				elif fcontent == "kad9":
    149 					if sentence != {}:
    150 						container["sentences"].append(sentence)
    151 					continue
    152 				elif fcontent == "sad9":
    153 					if sentence != {}:
    154 						container["sentences"].append(sentence)
    155 					continue
    156 				else:
    157 					sentence = {}
    158 					sentence["name"] = fcontent
    159 					sentence["fields"] = []
    160 					container["sentences"].append(sentence)
    161 
    162 					# Filter out special data.
    163 					if sentence["name"] == "besa":
    164 						besa = sentence
    165 					elif sentence["name"] == "rvsa":
    166 						rvsa = sentence
    167 					elif sentence["name"] == "adt0":
    168 						adt0 = sentence
    169 				continue
    170 			else:
    171 				if "fields" in sentence:
    172 					sentence["fields"].append([fieldid,
    173 						fcontent])
    174 				else:
    175 					container["fields"].append([fieldid,
    176 						fcontent])
    177 
    178 	besa = sentence2dict(besa)
    179 	rvsa = sentence2dict(rvsa)
    180 	adt0 = sentence2dict(adt0)
    181 
    182 	ambscheine = 0
    183 	notfallscheine = 0
    184 	ueberweisungen = 0
    185 	belegarztscheine = 0
    186 	for sentence in containers[0]["sentences"]:
    187 		if sentence["name"] == "0101":
    188 			ambscheine += 1
    189 		elif sentence["name"] == "0104":
    190 			notfallscheine += 1
    191 		elif sentence["name"] == "0102":
    192 			ueberweisungen += 1
    193 		elif sentence["name"] == "0103":
    194 			belegarztscheine +=1
    195 
    196 	gesamtscheine = ambscheine + notfallscheine + ueberweisungen + \
    197 			belegarztscheine
    198 
    199 	# Anonymisation dictionaries.
    200 	# All ICD codes, multiple codes per patient.
    201 	icdcodes = {}
    202 	# ICD codes, one per patient.
    203 	icdcodespp = {}
    204 	# All EBM codes, multiple codes per patient.
    205 	ebmcodes = {}
    206 	# EBM codes, one per patient.
    207 	ebmcodespp = {}
    208 
    209 	for sentence in containers[0]["sentences"]:
    210 		icdcodefound = 0
    211 		ebmcodefound = 0
    212 		for field in sentence["fields"]:
    213 			if field[0] == 5001:
    214 				if field[1] in ebmcodes:
    215 					ebmcodes[field[1]] += 1
    216 				else:
    217 					ebmcodes[field[1]] = 1
    218 
    219 				if ebmcodefound == 0:
    220 					if field[1] in ebmcodespp:
    221 						ebmcodespp[field[1]] += 1
    222 					else:
    223 						ebmcodespp[field[1]] = 1
    224 				else:
    225 					ebmcodefound = 1
    226 			elif field[0] == 6001:
    227 				if field[1] in icdcodes:
    228 					icdcodes[field[1]] += 1
    229 				else:
    230 					icdcodes[field[1]] = 1
    231 
    232 				if icdcodefound == 0:
    233 					if field[1] in icdcodespp:
    234 						icdcodespp[field[1]] += 1
    235 					else:
    236 						icdcodespp[field[1]] = 1
    237 				else:
    238 					icdcodefound = 1
    239 
    240 	def sortdict(d):
    241 		return sorted(d.items(), key=lambda kv: kv[1])[::-1]
    242 
    243 	def printtopic(topic):
    244 		global topicno
    245 		print("%d.) %s" % (topicno, topic))
    246 		topicno += 1
    247 
    248 	oicdcodes = sortdict(icdcodes)
    249 	oebmcodes = sortdict(ebmcodes)
    250 
    251 	print("SaxoForN-Datenerhebung:")
    252 	print("")
    253 
    254 	printtopic("PVS")
    255 	pvshersteller = None
    256 	if "111" in adt0:
    257 		if "dv@data-vital.de" in adt0["111"][0]:
    258 			pvshersteller = "DATA VITAL"
    259 	print("PVS-Hersteller = %s" % (pvshersteller))
    260 	print("")
    261 
    262 	printtopic("Gesamtscheine")
    263 	# KBV_ITA_VGEX_Datensatzbeschreibung_KVDT.pdf#S27
    264 	print("amb. Scheine ..... %d" % (ambscheine))
    265 	print("Notfallscheine ... %d" % (notfallscheine))
    266 	print("Ueberweisungen ... %d" % (ueberweisungen))
    267 	print("Belegarztscheine . %d" % (belegarztscheine))
    268 	print("=========================")
    269 	print("Gesamtscheine .... %d" % (gesamtscheine))
    270 	print("")
    271 
    272 	printtopic("Grundpauschalen")
    273 	for grundpauschale in ["03001", "04001", "03002", "04002",\
    274 			"03003", "04003", "03004", "04004", "03005",\
    275 			"04005"]:
    276 		printcode(ebmcodespp, grundpauschale)
    277 	print("")
    278 
    279 	printtopic("Privatpatienten")
    280 	# Consart "P"
    281 	# Ziffer "1"
    282 	print("")
    283 
    284 	#printtopic("AU-Anfragen")
    285 	#    Krankschreibung: "AU:"
    286 
    287 	printtopic("Anfragen Krankenkassen Muster 52")
    288 	printcode(ebmcodespp, "01622")
    289 	print("")
    290 
    291 	#printtopic("Einweisungen")
    292 	# TODO: Parse BDT.
    293 	# In Bemerkungsfeld:
    294 	#    Einweisungen: "KH:"
    295 	#    Ueberweisungen: "UE:"
    296 	#    Krankschreibung: "AU:"
    297 	#    Transportschein: "TA:"
    298 	#    Laborbemerkung: "UL:" 
    299 	#print("")
    300 
    301 	printtopic("COVID-19 Nachweise, PCR-Teste")
    302 	printcode(ebmcodespp, "88315")
    303 
    304 	sachsencovid19 = ["99136", "88240", "02402", "32006"]
    305 	print("Sachsen: %s = %d" % (sachsencovid19,\
    306 		ebmcodeoccurence(containers[0], sachsencovid19)))
    307 	hessencovid19 = ["88240", "02402"]
    308 	print("Hessen: %s = %d" % (hessencovid19,\
    309 		ebmcodeoccurence(containers[0], hessencovid19)))
    310 	print("")
    311 
    312 	printtopic("COVID-19 ICDs")
    313 	for covid19icd in ["U07.1", "U07.2", "U09.9", "U08.9", "U10.9", "U12.9"]:
    314 		printcode(icdcodes, covid19icd)
    315 	print("")
    316 
    317 	printtopic("Videosprechstunde")
    318 	videosprechstunde = ["01450", "40129", "40128", "01444",\
    319 			"01442"]
    320 	print("EBM-Codes: %s = %d" % (videosprechstunde,\
    321 			ebmcodeoccurence(containers[0],\
    322 			videosprechstunde)))
    323 	print("Bitte Videosprechstundeanbieter heraussuchen.")
    324 	print("")
    325 
    326 	printtopic("Hausbesuche")
    327 	arzthausbesuche = ["01410", "01411", "01412", "01413", "01415"]
    328 	naepahausbesuche = ["03062", "03063", "38100"]
    329 	impfhausbesuche = ["88323", "88324"]
    330 
    331 	print("Arzthaubesuche: %s = %d" % (arzthausbesuche,
    332 		ebmcodesumoccurence(containers[0], arzthausbesuche)))
    333 	print("Naepahaubesuche: %s = %d" % (naepahausbesuche,
    334 		ebmcodesumoccurence(containers[0], naepahausbesuche)))
    335 	print("Impfhausbesuche: %s = %d" % (impfhausbesuche,
    336 		ebmcodesumoccurence(containers[0], impfhausbesuche)))
    337 	print("")
    338 
    339 	printtopic("App auf Rezept")
    340 	# Rezept "Digitale Gesundheitsanwendung"
    341 	print("")
    342 
    343 	printtopic("ePA-Nutzung")
    344 	printcode(icdcodes, "88270")
    345 	print("TI-Anbindung? ja/nein")
    346 	print("Update auf ePA-Konnektor? ja/nein")
    347 	print("PVS-Modul ePA? ja/nein")
    348 	print("eHBA 2.0 bestellt? ja/nein")
    349 	print("Keine Anschaffung bisher? ja/nein")
    350 	print("")
    351 
    352 	print("Influenza-Impfungen")
    353 	influenza = ["89111", "89111S", "89112", "89112Y"]
    354 	printcodes(ebmcodes, influenza)
    355 	print("")
    356 
    357 	print("Pneumokokken-Impfung")
    358 	pneumokokken = ["89119", "89119R",\
    359 			"89120", "89120R",\
    360 			"89120V", "89120X"]
    361 	printcodes(ebmcodes, pneumokokken)
    362 	print("")
    363 
    364 	printtopic("COVID-19-Impfungen")
    365 	biontech = ["88331A", "88331B", "88331R",\
    366 			"88331G", "88331H", "88331K",\
    367 			"88331V", "88331W", "88331X"]
    368 	printcodes(ebmcodes, biontech)
    369 	biontechneu = ["88337A", "88337B",\
    370 			"88337V", "88337W",\
    371 			"88337G", "88337H",\
    372 			"88337K", "88337X"]
    373 	printcodes(ebmcodes, biontechneu)
    374 	moderna = ["88332A", "88332B", "88332R",\
    375 			"88332G", "88332H", "88332K",\
    376 			"88332V", "88332W", "88332X"]
    377 	printcodes(ebmcodes, moderna)
    378 	johnsonjohnson = ["88334", "88334R",\
    379 			"88334I", "88334K",\
    380 			"88334Y", "88334X"]
    381 	printcodes(ebmcodes, johnsonjohnson)
    382 	astrazeneca = ["88333A", "88333B", "88333R",\
    383 			"88333G", "88333H", "88333K",\
    384 			"88333V", "88333W", "88333X"]
    385 	printcodes(ebmcodes, astrazeneca)
    386 	novavax = ["88335A", "88335B",\
    387 			"88335V", "88335W",\
    388 			"88335G", "88335H",
    389 			"88335R", "88335K",
    390 			"88335X"]
    391 	printcodes(ebmcodes, novavax)
    392 	valneva = ["88336A", "88336B",\
    393 			"88336V", "88336W",\
    394 			"88336G", "88336H"]
    395 	printcodes(ebmcodes, valneva)
    396 	sanofi = ["88339A", "88339B",\
    397 			"88339V", "88339W",\
    398 			"88339G", "88339H",
    399 			"88339R", "88339K",
    400 			"88339X"]
    401 	printcodes(ebmcodes, valneva)
    402 	print("")
    403 
    404 	printcodes(ebmcodes, ["88125"])
    405 	print("")
    406 
    407 	printtopic("Schilddrüsenerkrankungen")
    408 	printcodessum(icdcodes, ["E01.0", "E01.1", "E01.2"])
    409 	printcodessum(icdcodes, ["E02"])
    410 	printcodessum(icdcodes, ["E03.-"])
    411 	printcodessum(icdcodes, ["E04.-"])
    412 	printcodessum(icdcodes, ["E05.-"])
    413 	printcodessum(icdcodes, ["E06.-"])
    414 	printcodessum(icdcodes, ["E07.-"])
    415 	printcodessum(icdcodes, ["D34.-"])
    416 	print("")
    417 
    418 	printtopic("Schilddrüsensonographie")
    419 	printcodes(ebmcodes, ["33012"])
    420 	print("")
    421 
    422 	return 0
    423 
    424 if __name__ == "__main__":
    425 	sys.exit(main(sys.argv))
    426