def reconciliation_step_3(rec_list_1=[], rec_list_2=[], unparsed_meds_1=[], unparsed_meds_2=[], rec=[], stats={}): """Helper function to handle matching by brand names.""" print "********** RECONCILIATION STEP 3 **********" print # Unpack the lists produced by the regular expression.findall, # and restore missing meds if they couldn't be parsed # rec_bn is a MatchResult object with the results of matching by brand name rec_bn = match_by_brand_name(rec_list_1, rec_list_2) pb1, pb2, bnrec = rec_bn.list1, rec_bn.list2, rec_bn.reconciled left1 = pb1 + unparsed_meds_1 left2 = pb2 + unparsed_meds_2 print "List 1 after brand name matching=\n", '\n'.join([str(x) for x in left1]) print print "List 2 after brand name matching=\n", '\n'.join([str(x) for x in left2]) print print "Reconciled after brand name matching=\n", '\n'.join([str(x) for x in bnrec]) print if stats is not None: stats['reconciled_brand_name'] = len(bnrec) already_reconciled = [x for x in bnrec] + rec print "All reconciled=\n", '\n'.join([str(x) for x in already_reconciled]) print "********** END OF STEP 3 **********" return dict( pb1=pb1, pb2=pb2, unparsed_meds_1=unparsed_meds_1, unparsed_meds_2=unparsed_meds_2, already_reconciled=already_reconciled, stats=stats )
def reconciliation_step_2(rec_list_1=[], rec_list_2=[], rec=[], stats={}): """Helper function to handle matching by brand names.""" print "********** RECONCILIATION STEP 2 **********" print # Separate parsed and unparsed medications parsed_meds_1, unparsed_meds_1 = separate_parsed_from_unparsed(rec_list_1) parsed_meds_2, unparsed_meds_2 = separate_parsed_from_unparsed(rec_list_2) # Unpack the lists produced by the regular expression.findall, # and restore missing meds if they couldn't be parsed print # rec_bn is a MatchResult object with the results of matching by brand name rec_bn = match_by_brand_name(parsed_meds_1, parsed_meds_2) pb1, pb2, bnrec = rec_bn.list1, rec_bn.list2, rec_bn.reconciled left1 = pb1 + unparsed_meds_1 left2 = pb2 + unparsed_meds_2 print "List 1 after brand name matching=\n", '\n'.join([str(x) for x in left1]) print print "List 2 after brand name matching=\n", '\n'.join([str(x) for x in left2]) print print "Reconciled after brand name matching=\n", '\n'.join([str(x) for x in bnrec]) print if stats is not None: stats['reconciled_brand_name'] = len(bnrec) already_reconciled = [x for x in bnrec] + rec.reconciled print "All reconciled=\n", '\n'.join([str(x) for x in already_reconciled]) print "********** END OF STEP 2 **********" return dict( pb1=pb1, pb2=pb2, unparsed_meds_1=unparsed_meds_1, unparsed_meds_2=unparsed_meds_2, already_reconciled=already_reconciled, stats=stats )
class TestFunctions(unittest.TestCase): """A set of unit tests to exercise the functions in the 'match' module. """ medString1 = 'Lisinopril 5 MG Tablet;TAKE TABLET TWICE DAILY; Rx' pMed1 = ParsedMedication(medString1, mappings) pMed1CUIs = set(['C0065374']) pMed1Tradenames = [ 'C0591228', 'C0591229', 'C0678140', 'C0701176', 'C0722805', 'C1602677', 'C2368718', 'C2368722', 'C2368725' ] medString2 = 'Pramipexole 0.5 MG Tablet;TAKE 1 TABLET 3 TIMES DAILY.; Rx' pMed2 = ParsedMedication(medString2, mappings) pMed2CUIs = set(['C0074710']) pMed2Tradenames = ['C0721754'] medString2a = 'PRAMIPEXOLE 0.5 MG TABLET;take 1 tablet 3 times daily.; rx' pMed2a = ParsedMedication(medString2a, mappings) pMed2aCUIs = set(['C0074710']) pMed2aTradenames = ['C0721754'] medString2b = 'Mirapex 0.5 MG Tablet;TAKE 1 TABLET 3 TIMES DAILY.; Rx' pMed2b = ParsedMedication(medString2b, mappings) pMed2bCUIs = set(['C0721754']) pMed2bTradenames = [] medString3 = 'Warfarin Sodium 2.5 MG Tablet;TAKE AS DIRECTED.; Rx' pMed3 = ParsedMedication(medString3, mappings) pMed3CUIs = set(['C0376218']) pMed3Tradenames = [] medString4 = 'Protonix 40 MG Tablet Delayed Release;TAKE 1 TABLET DAILY.; Rx' pMed4 = ParsedMedication(medString4, mappings) medString5 = 'Pantoprazole Sodium 40 MG Tablet Delayed Release;TAKE 1 TABLET DAILY.; Rx' pMed5 = ParsedMedication(medString5, mappings) medString6 = 'Paroxetine 20 MG Tablet; TAKE 1 TABLET DAILY.; Rx' pMed6 = ParsedMedication(medString6, mappings) medString7 = 'Sertraline 50 MG Tablet;TAKE 1 TABLET BY MOUTH EVERY DAY; Rx' pMed7 = ParsedMedication(medString7, mappings) medString8 = 'Razadyne 16 MG Capsule Extended Release 24 Hour;TAKE 1 CAPSULE DAILY IN THE MORNING take with meal daily; Rx.' pMed8 = ParsedMedication(medString8, mappings) medString9 = 'Cyclandelate 16 MG Capsule Extended Release 24 Hour;TAKE 1 CAPSULE DAILY IN THE MORNING take with meal daily; Rx.' pMed9 = ParsedMedication(medString9, mappings) medString10 = 'docosahexaenoic acid 200 mg capsules; one cap BID' pMed10 = ParsedMedication(medString10, mappings) medString11 = 'Exelon 4.6 MG/24HR Transdermal Patch 24 Hour;APPLY 1 PATCH DAILY AS DIRECTED.; Rx' pMed11 = ParsedMedication(medString11, mappings) list1 = [pMed1, pMed2] list1rev = [pMed2, pMed1] list2 = [pMed2a, pMed3] list2rev = [pMed3, pMed2a] list3 = [pMed2b, pMed3] list3rev = [pMed3, pMed2b] medication_list_test_CUIs = [ pMed1CUIs, pMed2CUIs, pMed2aCUIs, pMed3CUIs, pMed2bCUIs, pMed3CUIs ] medication_list_test_tradenames = [ pMed1Tradenames, pMed2Tradenames, pMed2aTradenames, pMed3Tradenames, pMed2bTradenames, pMed3Tradenames ] test_objects = None if test_match_objects: test_objects = test_match_objects['TestFunctions'] matched_by_strings = match.match_by_strings(list1, list2) matched_by_strings_rev = match.match_by_strings(list1rev, list2rev) if mappings: matched_by_brand_name1 = match.match_by_brand_name(list1, list3) matched_by_brand_name1_rev = match.match_by_brand_name( list1rev, list3rev) matched_by_brand_name2 = match.match_by_brand_name(list3, list1) matched_by_ingredients_above = match.match_by_ingredients( [pMed4], [pMed5], min_match_threshold=0.6) matched_by_ingredients_below = match.match_by_ingredients( [pMed4], [pMed5], min_match_threshold=0.7) matched_by_ingredients_rev_above = match.match_by_ingredients( [pMed5], [pMed4], min_match_threshold=0.6) matched_by_ingredients_rev_below = match.match_by_ingredients( [pMed5], [pMed4], min_match_threshold=0.7) if mappings.treatment: matched_by_treatment_above = match.match_by_treatment( [pMed6], [pMed7], mappings, match_acceptance_threshold=0.3) matched_by_treatment_below = match.match_by_treatment([pMed6], [pMed7], mappings) matched_by_treatment_05_yes = match.match_by_treatment( [pMed8], [pMed9], mappings, match_acceptance_threshold=0.5) matched_by_treatment_05_no = match.match_by_treatment( [pMed8], [pMed9], mappings, match_acceptance_threshold=0.51) matched_by_treatment_04_yes = match.match_by_treatment( [pMed10], [pMed11], mappings, match_acceptance_threshold=0.4) matched_by_treatment_04_no = match.match_by_treatment( [pMed10], [pMed11], mappings, match_acceptance_threshold=0.43) # Use the demo lists for testing; this code was previously in TestMatchResult demo_list_1 = [ pm for pm in [ make_medication(x, mappings, "List 1") for x in constants.demo_list_1 ] if isinstance(pm, ParsedMedication) ] demo_list_2 = [ pm for pm in [ make_medication(x, mappings, "List 2") for x in constants.demo_list_2 ] if isinstance(pm, ParsedMedication) ] demo_matched_by_strings = match.match_by_strings(demo_list_1, demo_list_2) demo_matched_by_strings_rev = match.match_by_strings( demo_list_2, demo_list_1) if mappings: demo_matched_by_brand_name = match.match_by_brand_name( demo_list_1, demo_list_2) demo_matched_by_brand_name_rev = match.match_by_brand_name( demo_list_2, demo_list_1) demo_matched_by_ingredients = match.match_by_ingredients( demo_list_1, demo_list_2) demo_matched_by_ingredients_rev = match.match_by_ingredients( demo_list_2, demo_list_1) @unittest.skipUnless(test_objects, 'missing test_match data') def test_match_by_strings(self): "Test that the MatchResult from a by-string match contains the lists we expect." self.assertEqual(self.matched_by_strings, self.test_objects['matched_by_strings']) @unittest.skipUnless(test_objects, 'missing test_match data') def test_match_by_strings_rev(self): """Test that the MatchResult from a by-string match is order-independent with respect to the order the medication lists are passed in.""" self.assertEqual(self.matched_by_strings_rev, self.test_objects['matched_by_strings_rev']) @unittest.skipUnless(mappings, 'missing MappingContext with RXNORM data') def test_medication_list_CUIs(self): "Test the operation of match.medication_list_CUIs()" cuis = match.medication_list_CUIs(self.list1 + self.list2 + self.list3) self.assertEqual(cuis, self.medication_list_test_CUIs) @unittest.skipUnless(mappings, 'missing MappingContext with RXNORM data') @unittest.skipUnless(test_objects, 'missing test_match data') def test_medication_list_tradenames(self): "Test the operation of match.medication_list_tradenames()" tradenames = match.medication_list_tradenames(self.list1 + self.list2 + self.list3) self.assertEqual(tradenames, self.medication_list_test_tradenames) @unittest.skipUnless(mappings, 'missing MappingContext with RXNORM data') @unittest.skipUnless(test_objects, 'missing test_match data') def test_match_by_brand_name1(self): """Test that the MatchResult from a by-brand-name match contains the lists we expect.""" self.assertEqual(self.matched_by_brand_name1, self.test_objects['matched_by_brand_name1']) @unittest.skipUnless(mappings, 'missing MappingContext with RXNORM data') @unittest.skipUnless(test_objects, 'missing test_match data') def test_match_by_brand_name1_rev(self): """Test that the MatchResult from a by-brand-name match is order-independent with respect to the order the medication lists are passed in.""" self.assertEqual(self.matched_by_brand_name1_rev, self.test_objects['matched_by_brand_name1_rev']) @unittest.skipUnless(mappings, 'missing MappingContext with RXNORM data') @unittest.skipUnless(test_objects, 'missing test_match data') def test_match_by_brand_name2(self): """Test that the MatchResult from a by-brand-name match contains the lists we expect.""" self.assertEqual(self.matched_by_brand_name2, self.test_objects['matched_by_brand_name2']) @unittest.skipUnless(mappings, 'missing MappingContext with RXNORM data') @unittest.skipUnless(test_objects, 'missing test_match data') def test_match_by_ingredients_above(self): """Test reconcilation of medications by treatment intent that should match at a threshold of 0.6.""" self.assertEqual(self.matched_by_ingredients_above, self.test_objects['matched_by_ingredients_above']) @unittest.skipUnless(mappings, 'missing MappingContext with RXNORM data') @unittest.skipUnless(test_objects, 'missing test_match data') def test_match_by_ingredients_below(self): """Test reconcilation of medications by treatment intent that should not match at a threshold of 0.7.""" self.assertEqual(self.matched_by_ingredients_below, self.test_objects['matched_by_ingredients_below']) @unittest.skipUnless(mappings, 'missing MappingContext with RXNORM data') @unittest.skipUnless(test_objects, 'missing test_match data') def test_match_by_ingredients_rev_above(self): """Test order independence of the reconcilation of medications by treatment intent that should match at a threshold of 0.6.""" self.assertEqual(self.matched_by_ingredients_rev_above, self.test_objects['matched_by_ingredients_rev_above']) @unittest.skipUnless(mappings, 'missing MappingContext with RXNORM data') @unittest.skipUnless(test_objects, 'missing test_match data') def test_match_by_ingredients_rev_below(self): """Test order independence of the reconcilation of medications by treatment intent that should not match at a threshold of 0.7.""" self.assertEqual(self.matched_by_ingredients_rev_below, self.test_objects['matched_by_ingredients_rev_below']) @unittest.skipUnless(test_objects, 'missing test_objects data') def test_demo_match_by_strings(self): """Use demo lists to test matching by strings.""" self.assertEqual(self.demo_matched_by_strings, self.test_objects['demo_matched_by_strings']) @unittest.skipUnless(test_objects, 'missing test_objects data') def test_demo_match_by_strings_rev(self): """Use demo lists to test order independence of matching by strings.""" self.assertEqual(self.demo_matched_by_strings_rev, self.test_objects['demo_matched_by_strings_rev']) @unittest.skipUnless(mappings, 'missing MappingContext with RXNORM data') @unittest.skipUnless(mappings and test_objects, 'missing MappingContext with RXNORM data') def test_demo_match_by_brand_name(self): """Use demo lists to test matching by brand names.""" self.assertEqual(self.demo_matched_by_brand_name, self.test_objects['demo_matched_by_brand_name']) @unittest.skipUnless(mappings, 'missing MappingContext with RXNORM data') @unittest.skipUnless(mappings and test_objects, 'missing MappingContext with RXNORM data') def test_demo_match_by_brand_name_rev(self): """Use demo lists to test order independence of matching by brand names.""" self.assertEqual(self.demo_matched_by_brand_name_rev, self.test_objects['demo_matched_by_brand_name_rev']) @unittest.skipUnless(mappings, 'missing MappingContext with RXNORM data') @unittest.skipUnless(mappings and test_objects, 'missing MappingContext with RXNORM data') def test_demo_match_by_ingredients_list(self): """Use demo lists to test matching by ingredients.""" self.assertEqual(self.demo_matched_by_ingredients, self.test_objects['demo_matched_by_ingredients']) @unittest.skipUnless(mappings, 'missing MappingContext with RXNORM data') @unittest.skipUnless(test_objects, 'missing test_match data') def test_demo_match_by_ingredients_list_rev(self): """Use demo lists to test order independence of matching by ingredients.""" self.assertEqual(self.demo_matched_by_ingredients_rev, self.test_objects['demo_matched_by_ingredients_rev']) @unittest.skipUnless(mappings, 'missing MappingContext with RXNORM data') @unittest.skipUnless(mappings and mappings.treatment, 'MappingContext lacks treatment data') def test_match_by_treatment_above(self): """These two medications should match by treatment if the match_acceptance_threshold is set to 0.3; note that this behavior may change as the underlying 'treats' data change.""" self.assertEqual(len(self.matched_by_treatment_above.reconciled), 1) @unittest.skipUnless(mappings, 'missing MappingContext with RXNORM data') @unittest.skipUnless(mappings and mappings.treatment, 'MappingContext lacks treatment data') def test_match_by_treatment_below(self): """These two medications should not match by treatment if the match_acceptance_threshold is set to default (0.5); note that this behavior may change as the underlying 'treats' data change.""" self.assertEqual(len(self.matched_by_treatment_below.reconciled), 0) @unittest.skipUnless(mappings, 'missing MappingContext with RXNORM data') @unittest.skipUnless(mappings and mappings.treatment, 'MappingContext lacks treatment data') def test_match_by_treatment_varies(self): """Test matching by treatment intent, varying thresholds to induce matches and non-matches on the same two sets of medication lists. """ self.assertEqual(len(self.matched_by_treatment_05_yes.reconciled), 1) self.assertEqual(len(self.matched_by_treatment_05_no.reconciled), 0) self.assertEqual(len(self.matched_by_treatment_04_yes.reconciled), 1) self.assertEqual(len(self.matched_by_treatment_04_no.reconciled), 0)