1919
2020def save_output_files (clm ,clm_line ,clm_val ,clm_dt_sgntr ,clm_prod ,clm_instnl ,clm_line_instnl ,clm_dcmtn ,clm_fiss ,clm_prfnl ,clm_line_prfnl ,clm_line_rx ):
2121 Path ("out" ).mkdir (exist_ok = True )
22+
2223 df = pd .json_normalize (clm )
2324 df ['CLM_BLOOD_PT_FRNSH_QTY' ] = df ['CLM_BLOOD_PT_FRNSH_QTY' ].astype ('Int64' )
25+ df ['CLM_BLG_PRVDR_OSCAR_NUM' ] = df ['CLM_BLG_PRVDR_OSCAR_NUM' ].astype ('string' )
26+ # Columns you want as string without decimal/nan
27+ int_to_string_cols = [
28+ 'CLM_TYPE_CD' , 'CLM_NUM_SK' , 'PRVDR_PRSCRBNG_PRVDR_NPI_NUM' ,
29+ 'PRVDR_RFRG_PRVDR_NPI_NUM' , 'PRVDR_BLG_PRVDR_NPI_NUM' ,
30+ 'CLM_ATNDG_PRVDR_NPI_NUM' , 'CLM_OPRTG_PRVDR_NPI_NUM' ,
31+ 'CLM_OTHR_PRVDR_NPI_NUM' , 'CLM_RNDRG_PRVDR_NPI_NUM'
32+ ]
33+
34+ for col in int_to_string_cols :
35+ df [col ] = (
36+ df [col ]
37+ .astype ('Int64' ) # Handle floats like 1234.0 → 1234
38+ .astype ('string' ) # Pandas nullable string type
39+ .fillna ('' ) # Replace <NA> with empty string
40+ )
2441 df .to_csv ('out/SYNTHETIC_CLM.csv' , index = False )
42+
2543 df = pd .json_normalize (clm_line )
44+ df ['CLM_LINE_NUM' ] = df ['CLM_LINE_NUM' ].astype ('str' )
2645 df .to_csv ('out/SYNTHETIC_CLM_LINE.csv' , index = False )
2746 df = pd .json_normalize (clm_val )
2847 df .to_csv ('out/SYNTHETIC_CLM_VAL.csv' , index = False )
@@ -33,6 +52,7 @@ def save_output_files(clm,clm_line,clm_val,clm_dt_sgntr,clm_prod,clm_instnl,clm_
3352 df = pd .json_normalize (clm_instnl )
3453 df .to_csv ('out/SYNTHETIC_CLM_INSTNL.csv' , index = False )
3554 df = pd .DataFrame (clm_line_instnl )
55+ df ['CLM_LINE_NUM' ] = df ['CLM_LINE_NUM' ].astype ('str' )
3656 df .to_csv ('out/SYNTHETIC_CLM_LINE_INSTNL.csv' , index = False )
3757 df = pd .json_normalize (clm_dcmtn )
3858 df .to_csv ('out/SYNTHETIC_CLM_DCMTN.csv' , index = False )
@@ -41,6 +61,7 @@ def save_output_files(clm,clm_line,clm_val,clm_dt_sgntr,clm_prod,clm_instnl,clm_
4161 df = pd .json_normalize (clm_prfnl )
4262 df .to_csv ('out/SYNTHETIC_CLM_PRFNL.csv' , index = False )
4363 df = pd .json_normalize (clm_line_prfnl )
64+ df ['CLM_LINE_NUM' ] = df ['CLM_LINE_NUM' ].astype ('str' )
4465 df .to_csv ('out/SYNTHETIC_CLM_LINE_PRFNL.csv' , index = False )
4566 df = pd .json_normalize (clm_line_rx )
4667 df .to_csv ('out/SYNTHETIC_CLM_LINE_RX.csv' , index = False )
@@ -241,7 +262,7 @@ def gen_claim(bene_sk = '-1', min_date = '2018-01-01', max_date = str(date.today
241262 claim ['CLM' ]['CLM_ORIG_CNTL_NUM' ] = '' .join (random .choices (string .digits , k = 14 )) + '' .join (random .choices (string .ascii_uppercase ,k = 3 ))
242263 claim ['CLM' ]['CLM_PRNT_CNTL_NUM' ] = claim ['CLM' ]['CLM_ORIG_CNTL_NUM' ]
243264
244- if (claim [ 'CLM' ][ 'CLM_TYPE_CD' ] in (20 ,30 ,40 ,60 ,61 ,62 ,63 ,71 ,72 )):
265+ if (clm_type_cd in (20 ,30 ,40 ,60 ,61 ,62 ,63 ,71 ,72 )):
245266 claim ['CLM' ]['CLM_BLOOD_PT_FRNSH_QTY' ] = random .randint (0 ,20 )
246267
247268 claim ['CLM' ]['CLM_NUM_SK' ] = 1
@@ -263,21 +284,36 @@ def gen_claim(bene_sk = '-1', min_date = '2018-01-01', max_date = str(date.today
263284 claim ['CLM' ]['CLM_SBMTR_CNTRCT_NUM' ] = 'Z0001'
264285 claim ['CLM' ]['CLM_SBMTR_CNTRCT_PBP_NUM' ] = random .choice (avail_pbp_nums )
265286 claim_line = {}
287+ claim_line ['CLM_UNIQ_ID' ] = claim ['CLM' ]['CLM_UNIQ_ID' ]
288+ claim_line ['CLM_NUM_SK' ] = claim ['CLM' ]['CLM_NUM_SK' ]
289+ claim_line ['CLM_TYPE_CD' ] = claim ['CLM' ]['CLM_TYPE_CD' ]
290+ claim_line ['GEO_BENE_SK' ] = claim ['CLM' ]['GEO_BENE_SK' ]
291+ claim_line ['CLM_DT_SGNTR_SK' ] = claim ['CLM' ]['CLM_DT_SGNTR_SK' ]
266292 claim_line ['CLM_LINE_CVRD_PD_AMT' ] = round (random .uniform (1 , 1000000 ),2 )
267293 claim_line ['CLM_LINE_NCVRD_PD_AMT' ] = round (random .uniform (1 , 1000000 ),2 )
294+ claim_line ['CLM_LINE_NCVRD_CHRG_AMT' ] = round (random .uniform (0 ,1500 ),2 )
268295 claim_line ['CLM_LINE_NDC_CD' ] = random .choice (available_ndc )
269296 claim_line ['CLM_LINE_SRVC_UNIT_QTY' ] = random .randint (1 ,10 )
270- claim_line ['CLM_LINE_FROM_DT' ] = claim ['CLM' ]['CLM_FROM_DT' ]
297+ claim_line ['CLM_LINE_FROM_DT' ] = claim ['CLM' ]['CLM_FROM_DT' ]
298+ claim_line ['CLM_LINE_THRU_DT' ] = claim ['CLM' ]['CLM_THRU_DT' ]
271299 claim_line ['CLM_LINE_NDC_QTY' ] = random .randint (1 ,10 )
272300 claim_line ['CLM_LINE_NDC_QTY_QLFYR_CD' ] = 'ML'
273301 claim_line ['CLM_LINE_BENE_PD_AMT' ] = round (random .uniform (1 , 1000000 ),2 )
274302 claim_line ['CLM_LINE_PRVDR_PMT_AMT' ] = round (random .uniform (1 , 1000000 ),2 )
303+ claim_line ['CLM_LINE_SBMT_CHRG_AMT' ] = round (random .uniform (0 ,5 ),2 )
304+ claim_line ['CLM_LINE_BENE_PMT_AMT' ] = round (random .uniform (0 ,5 ),2 )
305+ claim_line ['CLM_LINE_BLOOD_DDCTBL_AMT' ] = round (random .uniform (0 ,15 ),2 )
306+ claim_line ['CLM_LINE_MDCR_DDCTBL_AMT' ] = round (random .uniform (0 ,5 ),2 )
307+ claim_line ['CLM_LINE_NUM' ] = '1'
308+ claim_line ['CLM_FROM_DT' ] = claim ['CLM' ]['CLM_FROM_DT' ]
275309
276310 claim_line_rx = {}
277311 claim_line_rx ['CLM_UNIQ_ID' ] = claim ['CLM' ]['CLM_UNIQ_ID' ]
278312 claim_line_rx ['CLM_NUM_SK' ] = claim ['CLM' ]['CLM_NUM_SK' ]
279313 claim_line_rx ['CLM_TYPE_CD' ] = claim ['CLM' ]['CLM_TYPE_CD' ]
280- claim_line_rx ['CLM_GEO_BENE_SK' ] = claim ['CLM' ]['GEO_BENE_SK' ]
314+ claim_line_rx ['GEO_BENE_SK' ] = claim ['CLM' ]['GEO_BENE_SK' ]
315+ claim_line_rx ['CLM_LINE_NUM' ] = '1'
316+ claim_line_rx ['CLM_FROM_DT' ] = claim ['CLM' ]['CLM_FROM_DT' ]
281317 claim_line_rx ['CLM_LINE_RX_ORGN_CD' ] = random .choice (generator .code_systems ['CLM_LINE_RX_ORGN_CD' ])
282318 claim_line_rx ['CLM_BRND_GNRC_CD' ] = random .choice (generator .code_systems ['CLM_BRND_GNRC_CD' ])
283319 claim_line_rx ['CLM_PTNT_RSDNC_CD' ] = random .choice (generator .code_systems ['CLM_PTNT_RSDNC_CD' ])
@@ -327,29 +363,26 @@ def gen_claim(bene_sk = '-1', min_date = '2018-01-01', max_date = str(date.today
327363 if (clm_type_cd in (1 ,2 ,3 ,4 ,10 ,20 ,30 ,40 ,50 ,60 ,61 ,62 ,63 ,71 ,72 ,81 ,82 )):
328364 clm_ltst_clm_ind = 'Y'
329365 claim ['CLM' ]['CLM_LTST_CLM_IND' ] = clm_ltst_clm_ind
330-
366+
367+ claim ['CLM_DCMTN' ]['CLM_DT_SGNTR_SK' ] = claim ['CLM' ]['CLM_DT_SGNTR_SK' ]
368+ claim ['CLM_DCMTN' ]['CLM_NUM_SK' ] = claim ['CLM' ]['CLM_NUM_SK' ]
369+ claim ['CLM_DCMTN' ]['GEO_BENE_SK' ] = claim ['CLM' ]['GEO_BENE_SK' ]
370+ claim ['CLM_DCMTN' ]['CLM_TYPE_CD' ] = claim ['CLM' ]['CLM_TYPE_CD' ]
331371
332372 #CLM_RIC_CDs are generally tied to the claim type code.
333- if (claim [ 'CLM' ][ 'CLM_TYPE_CD' ] in (20 ,30 ,50 ,60 ,61 ,62 ,63 ,64 )):
373+ if (clm_type_cd in (20 ,30 ,50 ,60 ,61 ,62 ,63 ,64 )):
334374 #part A!
335375 claim ['CLM_DCMTN' ]['CLM_NRLN_RIC_CD' ] = 'V' #inpatient
336- claim ['CLM_DCMTN' ]['CLM_DT_SGNTR_SK' ] = claim ['CLM' ]['CLM_DT_SGNTR_SK' ]
337- claim ['CLM_DCMTN' ]['CLM_NUM_SK' ] = claim ['CLM' ]['CLM_NUM_SK' ]
338- claim ['CLM_DCMTN' ]['GEO_BENE_SK' ] = claim ['CLM' ]['GEO_BENE_SK' ]
339- claim ['CLM_DCMTN' ]['CLM_TYPE_CD' ] = claim ['CLM' ]['CLM_TYPE_CD' ]
340- elif (claim ['CLM' ]['CLM_TYPE_CD' ] == 40 ):
376+ elif (clm_type_cd == 40 ):
341377 #outpatient
342378 claim ['CLM_DCMTN' ]['CLM_NRLN_RIC_CD' ] = 'W' #outpatient
343- claim ['CLM_DCMTN' ]['CLM_DT_SGNTR_SK' ] = claim ['CLM' ]['CLM_DT_SGNTR_SK' ]
344- claim ['CLM_DCMTN' ]['CLM_NUM_SK' ] = claim ['CLM' ]['CLM_NUM_SK' ]
345- claim ['CLM_DCMTN' ]['GEO_BENE_SK' ] = claim ['CLM' ]['GEO_BENE_SK' ]
346- claim ['CLM_DCMTN' ]['CLM_TYPE_CD' ] = claim ['CLM' ]['CLM_TYPE_CD' ]
347- elif (claim ['CLM' ]['CLM_TYPE_CD' ] == 10 ):
379+ elif (clm_type_cd == 10 ):
348380 claim ['CLM_DCMTN' ]['CLM_NRLN_RIC_CD' ] = random .choice (['U' ,'V' ,'W' ])
349- claim ['CLM_DCMTN' ]['CLM_DT_SGNTR_SK' ] = claim ['CLM' ]['CLM_DT_SGNTR_SK' ]
350- claim ['CLM_DCMTN' ]['CLM_NUM_SK' ] = claim ['CLM' ]['CLM_NUM_SK' ]
351- claim ['CLM_DCMTN' ]['GEO_BENE_SK' ] = claim ['CLM' ]['GEO_BENE_SK' ]
352- claim ['CLM_DCMTN' ]['CLM_TYPE_CD' ] = claim ['CLM' ]['CLM_TYPE_CD' ]
381+ elif (clm_type_cd in (71 , 72 )):
382+ claim ['CLM_DCMTN' ]['CLM_NRLN_RIC_CD' ] = 'O'
383+ elif (clm_type_cd in (81 , 82 )):
384+ claim ['CLM_DCMTN' ]['CLM_NRLN_RIC_CD' ] = 'M'
385+
353386 add_meta_timestamps (claim ['CLM_DCMTN' ], claim ['CLM' ], max_date )
354387
355388 #provider elements:
@@ -390,7 +423,7 @@ def gen_claim(bene_sk = '-1', min_date = '2018-01-01', max_date = str(date.today
390423
391424 claim ['CLM_VAL' ] = []
392425 #CLM_OPRTNL_DSPRTNT_AMT + CLM_OPRTNL_IME_AMT
393- if (claim [ 'CLM' ][ 'CLM_TYPE_CD' ] in (20 ,40 ,60 ,61 ,62 ,63 ,64 )):
426+ if (clm_type_cd in (20 ,40 ,60 ,61 ,62 ,63 ,64 )):
394427 #Note, this is a table we'll use sparsely, it appears. I've replaced the 5 key unique identifier with CLM_UNIQ_ID.
395428 clm_val_dsprtnt = {'CLM_DT_SGNTR_SK' :claim ['CLM' ]['CLM_DT_SGNTR_SK' ],
396429 'CLM_NUM_SK' :claim ['CLM' ]['CLM_NUM_SK' ],
@@ -524,6 +557,7 @@ def gen_claim(bene_sk = '-1', min_date = '2018-01-01', max_date = str(date.today
524557 claim ['CLM_PRFNL' ]['CLM_MDCR_PRFNL_PRMRY_PYR_AMT' ] = round (random .uniform (10 ,1000 ),2 )
525558 claim ['CLM_PRFNL' ]['CLM_MDCR_PRFNL_PRVDR_ASGNMT_SW' ] = random .choice (generator .code_systems ['CLM_MDCR_PRFNL_PRVDR_ASGNMT_SW' ])
526559 claim ['CLM_PRFNL' ]['CLM_CLNCL_TRIL_NUM' ] = str (random .randint (0 ,10000 ))
560+ add_meta_timestamps (claim ['CLM_PRFNL' ], claim ['CLM' ], max_date )
527561
528562
529563 num_clm_lines = random .randint (1 ,15 )
@@ -539,6 +573,8 @@ def gen_claim(bene_sk = '-1', min_date = '2018-01-01', max_date = str(date.today
539573 claim_line ['CLM_TYPE_CD' ] = claim ['CLM' ]['CLM_TYPE_CD' ]
540574 claim_line ['CLM_NUM_SK' ] = claim ['CLM' ]['CLM_NUM_SK' ]
541575 claim_line ['CLM_FROM_DT' ] = claim ['CLM' ]['CLM_FROM_DT' ]
576+ claim_line ['CLM_LINE_FROM_DT' ] = claim ['CLM' ]['CLM_FROM_DT' ]
577+ claim_line ['CLM_LINE_THRU_DT' ] = claim ['CLM' ]['CLM_THRU_DT' ]
542578 if (clm_type_cd >= 10 and clm_type_cd <= 64 ):
543579 claim_line_inst ['GEO_BENE_SK' ] = claim ['CLM' ]['GEO_BENE_SK' ]
544580 claim_line_inst ['CLM_DT_SGNTR_SK' ] = claim ['CLM' ]['CLM_DT_SGNTR_SK' ]
@@ -565,16 +601,13 @@ def gen_claim(bene_sk = '-1', min_date = '2018-01-01', max_date = str(date.today
565601
566602 if (random .randint (0 ,10 )== 6 ):
567603 claim_line_prfnl ['CLM_LINE_HCT_HGB_TYPE_CD' ] = random .choice (['R1' ,'R2' ])
568- claim_line_prfnl ['CLM_LINE_HCT_HGB_TYPE_CD' ] = round (random .uniform (0 ,1 ),2 )
569604 claim_line_prfnl ['CLM_LINE_CARR_CLNCL_LAB_NUM' ] = random .choice (['11D1111111' ,'22D2222222' ])
570605
571606
572607
573608
574609
575610 #these don't have much variance in our synthetic data, but they are not strictly the same in actual data!
576- claim_line ['CLM_LINE_FROM_DT' ] = claim ['CLM' ]['CLM_FROM_DT' ]
577- claim_line ['CLM_LINE_THRU_DT' ] = claim ['CLM' ]['CLM_THRU_DT' ]
578611 claim_line ['CLM_LINE_MDCR_COINSRNC_AMT' ] = round (random .uniform (0 ,5 ),2 )
579612
580613 #pick a random diagnosis.
@@ -585,7 +618,7 @@ def gen_claim(bene_sk = '-1', min_date = '2018-01-01', max_date = str(date.today
585618
586619 if (clm_type_cd >= 71 and clm_type_cd <= 72 ):
587620
588- claim_line ['CLM_RNDRG_PRVDR_TAX_NUM' ] = random .choice (['192834791234 ' ,'91283472987 ' ])
621+ claim_line ['CLM_RNDRG_PRVDR_TAX_NUM' ] = random .choice (['1928347912 ' ,'912834729 ' ])
589622 claim_line ['CLM_RNDRG_PRVDR_PIN_NUM' ] = random .choice (['29364819' ,'19238747' ])
590623 if (random .choice ([0 ,10 ])== 7 ):
591624 claim_line ['CLM_LINE_ANSTHSA_UNIT_CNT' ] = random .uniform (0 ,10 )
@@ -598,7 +631,7 @@ def gen_claim(bene_sk = '-1', min_date = '2018-01-01', max_date = str(date.today
598631 claim_line_prfnl ['CLM_LINE_PRFNL_DME_PRICE_AMT' ] = round (random .uniform (0 ,10000 ),2 )
599632 claim_line ['CLM_RNDRG_PRVDR_NPI_NUM' ] = random .choice (type_1_npis )
600633
601-
634+ add_meta_timestamps ( claim_line_prfnl , claim [ 'CLM' ], max_date )
602635
603636 claim_line ['CLM_LINE_HCPCS_CD' ] = random .choice (proc_codes_cpt_hcpcs )
604637 num_mods = random .randint (0 ,5 )
@@ -674,23 +707,24 @@ def gen_pac_version_of_claim(claim, max_date):
674707 '''
675708 pac_claim = copy .deepcopy (claim )
676709 pac_claim ['CLM' ]['CLM_UNIQ_ID' ] = '' .join (random .choices (string .digits , k = 13 ))
710+ pac_clm_type_cd = int (pac_claim ['CLM' ]['CLM_TYPE_CD' ])
677711
678- if (pac_claim [ 'CLM' ][ 'CLM_TYPE_CD' ] in (60 ,61 ,62 ,63 ,64 )):
712+ if (pac_clm_type_cd in (60 ,61 ,62 ,63 ,64 )):
679713 pac_claim ['CLM' ]['CLM_TYPE_CD' ] = random .choices ([1011 ,2011 ,1041 ,2041 ],weights = [.48 ,.48 ,.02 ,.02 ])[0 ]
680714
681- if (pac_claim [ 'CLM' ][ 'CLM_TYPE_CD' ] == 40 ):
715+ if (pac_clm_type_cd == 40 ):
682716 pac_claim ['CLM' ]['CLM_TYPE_CD' ] = random .choices ([1013 ,2013 ,1071 ,2071 ],weights = [.48 ,.48 ,.02 ,.02 ])[0 ]
683717
684- if (pac_claim [ 'CLM' ][ 'CLM_TYPE_CD' ] == 10 ):
718+ if (pac_clm_type_cd == 10 ):
685719 pac_claim ['CLM' ]['CLM_TYPE_CD' ] = random .choices ([1032 ,2032 ,1033 ,2033 ],weights = [.48 ,.48 ,.02 ,.02 ])[0 ]
686720
687- if (pac_claim [ 'CLM' ][ 'CLM_TYPE_CD' ] == 20 ):
721+ if (pac_clm_type_cd == 20 ):
688722 pac_claim ['CLM' ]['CLM_TYPE_CD' ] = random .choice ([1021 ,2021 ])
689723
690- if (pac_claim [ 'CLM' ][ 'CLM_TYPE_CD' ] == 30 ):
724+ if (pac_clm_type_cd == 30 ):
691725 pac_claim ['CLM' ]['CLM_TYPE_CD' ] = random .choices ([1018 ,2018 ])[0 ]
692726
693- if (pac_claim [ 'CLM' ][ 'CLM_TYPE_CD' ] == 50 ):
727+ if (pac_clm_type_cd == 50 ):
694728 pac_claim ['CLM' ]['CLM_TYPE_CD' ] = random .choices ([1081 ,2081 ,1082 ,2082 ],weights = [.48 ,.48 ,.02 ,.02 ])[0 ]
695729
696730 if ('CLM_BLOOD_PT_FRNSH_QTY' in pac_claim ['CLM' ]):
@@ -708,6 +742,7 @@ def gen_pac_version_of_claim(claim, max_date):
708742
709743
710744 for i in range (len (pac_claim ['CLM_LINE' ])):
745+ pac_claim ['CLM_LINE' ][i ]['CLM_LINE_NUM' ] = i + 1
711746 pac_claim ['CLM_LINE' ][i ]['CLM_UNIQ_ID' ] = pac_claim ['CLM' ]['CLM_UNIQ_ID' ]
712747 pac_claim ['CLM_LINE' ][i ]['GEO_BENE_SK' ] = pac_claim ['CLM' ]['GEO_BENE_SK' ]
713748 pac_claim ['CLM_LINE' ][i ]['CLM_DT_SGNTR_SK' ] = pac_claim ['CLM' ]['CLM_DT_SGNTR_SK' ]
@@ -920,9 +955,6 @@ def main():
920955 for line in pac_claim ['CLM_LINE_INSTNL' ]:
921956 CLM_LINE_INSTNL .append (line )
922957 CLM_FISS .append (pac_claim ['CLM_FISS' ])
923- CLM_PRFNL .append (pac_claim ['CLM_PRFNL' ])
924- for line in pac_claim ['CLM_LINE_PRFNL' ]:
925- CLM_LINE_PRFNL .append (line )
926958
927959 pt_complete += 1
928960 save_output_files (CLM ,CLM_LINE ,CLM_VAL ,CLM_DT_SGNTR ,CLM_PROD ,CLM_INSTNL ,CLM_LINE_INSTNL ,CLM_DCMTN ,CLM_FISS ,CLM_PRFNL ,CLM_LINE_PRFNL ,CLM_LINE_RX )
0 commit comments