### Execute Matching Pipeline Source: https://context7.com/pckhoi/datamatch/llms.txt A complete example demonstrating indexing, scoring, swapping, and threshold analysis in a matching pipeline. ```python import pandas as pd from datamatch import ( ThresholdMatcher, ColumnsIndex, MultiIndex, StringSimilarity, JaroWinklerSimilarity, DateSimilarity, DissimilarFilter, Swap ) # Source A: HR Database hr_data = pd.DataFrame({ 'emp_id': ['HR001', 'HR002', 'HR003', 'HR004'], 'first_name': ['John', 'Jane', 'Robert', 'Mary'], 'last_name': ['Smith', 'Doe', 'Johnson', 'Williams'], 'department': ['Engineering', 'Marketing', 'Engineering', 'HR'], 'hire_date': pd.to_datetime(['2020-01-15', '2019-06-01', '2021-03-10', '2018-11-20']) }).set_index('emp_id') # Source B: Payroll System payroll_data = pd.DataFrame({ 'pay_id': ['PAY001', 'PAY002', 'PAY003', 'PAY004'], 'first_name': ['Jon', 'Janet', 'Bob', 'Williams'], # Variations and swaps 'last_name': ['Smith', 'Doe', 'Johnson', 'Mary'], # Mary Williams swapped 'department': ['Engineering', 'Marketing', 'Engineering', 'HR'], 'hire_date': pd.to_datetime(['2020-01-15', '2019-06-05', '2021-03-10', '2018-11-20']) }).set_index('pay_id') # Create comprehensive matcher matcher = ThresholdMatcher( index=ColumnsIndex('department'), # Only compare within same department scorer={ 'first_name': JaroWinklerSimilarity(), # Good for name variations 'last_name': JaroWinklerSimilarity(), 'hire_date': DateSimilarity(d_max=30) # Allow 30 day tolerance }, dfa=hr_data, dfb=payroll_data, variator=Swap('first_name', 'last_name'), # Handle name swaps show_progress=True ) # Analyze results at different thresholds print("Sample pairs for threshold analysis:") print(matcher.get_sample_pairs(sample_counts=3, lower_bound=0.6)) # Get final matches threshold = 0.75 matched_pairs = matcher.get_index_pairs_within_thresholds(lower_bound=threshold) print(f"\nMatched pairs at threshold {threshold}:") for hr_id, pay_id in matched_pairs: print(f" {hr_id} <-> {pay_id}") ``` -------------------------------- ### Install Datamatch Library Source: https://context7.com/pckhoi/datamatch/llms.txt Install the datamatch library using pip. This command installs the package and its dependencies. ```bash pip install datamatch ``` -------------------------------- ### Initialize ThresholdMatcher Source: https://github.com/pckhoi/datamatch/blob/main/doc/tutorial.md Initializes the ThresholdMatcher with datasets to be matched and specifies the similarity function for each field. This is a basic setup for threshold-based classification. ```python matcher = ThresholdMatcher(datasets=datasets, left_on=['title'], right_on=['title'], similarities=[LevenshteinSimilarity()]) ``` -------------------------------- ### Initialize ThresholdMatcher with Index Source: https://github.com/pckhoi/datamatch/blob/main/doc/tutorial.md Initializes the ThresholdMatcher with datasets and specifies the similarity function, incorporating an index to optimize the matching process. This example uses ColumnsIndex based on the 'year' column. ```python matcher = ThresholdMatcher(datasets=datasets, left_on=['title'], right_on=['title'], similarities=[LevenshteinSimilarity()], idx=ColumnsIndex(left_on=['year'], right_on=['year'])) ``` -------------------------------- ### Data Matching with NoopIndex Source: https://context7.com/pckhoi/datamatch/llms.txt Use NoopIndex with ThresholdMatcher to compare all possible pairs of records without any indexing. This is suitable for small datasets where performance is not critical. The example uses StringSimilarity for 'name' matching. ```python import pandas as pd from datamatch import ThresholdMatcher, NoopIndex, StringSimilarity dfa = pd.DataFrame({'id': [1, 2], 'name': ['Alice', 'Bob']}).set_index('id') dfb = pd.DataFrame({'id': [3, 4], 'name': ['Alicia', 'Bobby']}).set_index('id') # NoopIndex compares all pairs (n x m comparisons) matcher = ThresholdMatcher( index=NoopIndex(), scorer={'name': StringSimilarity()}, dfa=dfa, dfb=dfb ) pairs = matcher.get_index_pairs_within_thresholds(lower_bound=0.5) print(pairs) # All pairs above 0.5 similarity ``` -------------------------------- ### Data Matching with ThresholdMatcher Source: https://context7.com/pckhoi/datamatch/llms.txt Use ThresholdMatcher for data matching between two DataFrames. Configure indexing and similarity scorers. This example demonstrates matching records based on the 'year' column and using Jaro-Winkler similarity for 'name'. ```python import pandas as pd from datamatch import ThresholdMatcher, ColumnsIndex, StringSimilarity, JaroWinklerSimilarity # Load two datasets to match dfa = pd.DataFrame({ 'id': [1, 2, 3], 'name': ['John Smith', 'Jane Doe', 'Bob Wilson'], 'year': [2020, 2021, 2020] }).set_index('id') dfb = pd.DataFrame({ 'id': [101, 102, 103], 'name': ['Jon Smith', 'Janet Doe', 'Robert Wilson'], 'year': [2020, 2021, 2020] }).set_index('id') # Create matcher with ColumnsIndex for performance and similarity functions matcher = ThresholdMatcher( index=ColumnsIndex('year'), # Only compare records from the same year scorer={ 'name': JaroWinklerSimilarity() # Use Jaro-Winkler for name matching }, dfa=dfa, dfb=dfb, show_progress=True # Show progress bar ) # Review sample pairs at different score ranges sample_pairs = matcher.get_sample_pairs(sample_counts=5, lower_bound=0.7) print(sample_pairs) # Get all matching pairs above threshold matched_pairs = matcher.get_index_pairs_within_thresholds(lower_bound=0.8) print(f"Matched pairs: {matched_pairs}") # [(1, 101), (2, 102), ...] # Get all pairs as DataFrame all_pairs_df = matcher.get_all_pairs(lower_bound=0.7) # Save results to Excel for review matcher.save_pairs_to_excel('matching_results.xlsx', match_threshold=0.8) matcher.print_decision(match_threshold=0.8) ``` -------------------------------- ### Deduplication with ThresholdMatcher Source: https://context7.com/pckhoi/datamatch/llms.txt Use ThresholdMatcher in deduplication mode by providing only one DataFrame. This finds duplicate records within the dataset. The example uses 'year' for indexing and StringSimilarity for 'title' and 'author'. ```python import pandas as pd from datamatch import ThresholdMatcher, ColumnsIndex, StringSimilarity # Dataset with potential duplicates df = pd.DataFrame({ 'id': [1, 2, 3, 4], 'title': ['Data Science Intro', 'Introduction to Data Science', 'Machine Learning', 'ML Basics'], 'author': ['Smith', 'Smith', 'Jones', 'Jones'], 'year': [2020, 2020, 2021, 2021] }).set_index('id') # Create matcher for deduplication (only one dataset provided) matcher = ThresholdMatcher( index=ColumnsIndex('year'), scorer={ 'title': StringSimilarity(), 'author': StringSimilarity() }, dfa=df # No dfb - triggers deduplication mode ) # Get clusters of duplicate records clusters = matcher.get_index_clusters_within_thresholds(lower_bound=0.6) print(f"Duplicate clusters: {clusters}") # [frozenset({1, 2}), frozenset({3, 4})] # Get detailed cluster information as DataFrame clusters_df = matcher.get_clusters_within_threshold(lower_bound=0.6) print(clusters_df) # Save clusters to Excel matcher.save_clusters_to_excel('dedup_results.xlsx', match_threshold=0.7) ``` -------------------------------- ### Save Detailed Matching Results to Excel Source: https://context7.com/pckhoi/datamatch/llms.txt Saves detailed matching results to an Excel file and prints the decision based on the match threshold. Ensure the 'pandas' library is installed for Excel export. ```python matcher.save_pairs_to_excel('hr_payroll_matching.xlsx', match_threshold=threshold) matcher.print_decision(match_threshold=threshold) ``` -------------------------------- ### Download DBLP-ACM Dataset Source: https://github.com/pckhoi/datamatch/blob/main/doc/deduplication.md Use this command to download and extract the DBLP-ACM dataset, which is used for demonstrating deduplication. ```bash unzip DBLP-ACM.zip -d DBLP-ACM ``` -------------------------------- ### Create Multi-Column Index with ColumnsIndex Source: https://context7.com/pckhoi/datamatch/llms.txt Employ ColumnsIndex with a list of column names to create buckets where records must match on all specified columns. This provides a more granular bucketing strategy. ```python # Multiple column index - records must match on both state AND year matcher2 = ThresholdMatcher( index=ColumnsIndex(['state', 'year']), scorer={'name': StringSimilarity()}, dfa=df ) ``` -------------------------------- ### Combine Indices with MultiIndex (AND Logic) Source: https://context7.com/pckhoi/datamatch/llms.txt Employ MultiIndex with `combine_keys=True` to implement AND logic, creating a cartesian product of keys from multiple indices. Records are matched only if they satisfy the conditions of all combined indices simultaneously. ```python # AND mode: match only if BOTH dept AND level are the same matcher_and = ThresholdMatcher( index=MultiIndex([ ColumnsIndex('dept'), ColumnsIndex('level') ], combine_keys=True), # AND logic scorer={'name': StringSimilarity()}, dfa=df ) ``` -------------------------------- ### Handle Column Swaps Source: https://context7.com/pckhoi/datamatch/llms.txt Use the Swap variator to account for data entry errors where values between two columns were swapped. ```python import pandas as pd from datamatch import ThresholdMatcher, NoopIndex, StringSimilarity, Swap # Dataset where some records have first/last names swapped dfa = pd.DataFrame({ 'id': [1, 2], 'first_name': ['John', 'Mary'], 'last_name': ['Smith', 'Johnson'] }).set_index('id') dfb = pd.DataFrame({ 'id': [3, 4], 'first_name': ['John', 'Johnson'], # id=4 has names swapped 'last_name': ['Smith', 'Mary'] }).set_index('id') # Without variator - might miss swapped name matches matcher_no_swap = ThresholdMatcher( index=NoopIndex(), scorer={ 'first_name': StringSimilarity(), 'last_name': StringSimilarity() }, dfa=dfa, dfb=dfb ) # With Swap variator - tries both original and swapped versions matcher_with_swap = ThresholdMatcher( index=NoopIndex(), scorer={ 'first_name': StringSimilarity(), 'last_name': StringSimilarity() }, dfa=dfa, dfb=dfb, variator=Swap('first_name', 'last_name') # Try swapping names ) pairs_no_swap = matcher_no_swap.get_index_pairs_within_thresholds(lower_bound=0.8) pairs_with_swap = matcher_with_swap.get_index_pairs_within_thresholds(lower_bound=0.8) print(f"Without swap: {pairs_no_swap}") print(f"With swap: {pairs_with_swap}") # Catches Mary Johnson match ``` -------------------------------- ### Index Based on List Elements with ColumnsIndex Source: https://context7.com/pckhoi/datamatch/llms.txt Utilize ColumnsIndex with `index_elements=True` when the column contains lists. This strategy creates buckets based on the overlap of elements within these lists, allowing matches if any element is shared. ```python df_tags = pd.DataFrame({ 'id': [1, 2, 3], 'name': ['Doc1', 'Doc2', 'Doc3'], 'tags': [['python', 'ml'], ['python', 'web'], ['ml', 'data']] }).set_index('id') matcher3 = ThresholdMatcher( index=ColumnsIndex('tags', index_elements=True), # Match if any tag overlaps scorer={'name': StringSimilarity()}, dfa=df_tags ) ``` -------------------------------- ### Combine Scores with SimSumScorer Source: https://context7.com/pckhoi/datamatch/llms.txt Aggregates similarity scores from multiple fields using a root-mean-square calculation. ```python import pandas as pd from datamatch import SimSumScorer, StringSimilarity, JaroWinklerSimilarity scorer = SimSumScorer({ 'first_name': JaroWinklerSimilarity(), 'last_name': StringSimilarity(), 'email': StringSimilarity() }) rec_a = pd.Series({ 'first_name': 'John', 'last_name': 'Smith', 'email': 'john.smith@email.com' }) rec_b = pd.Series({ 'first_name': 'Jon', 'last_name': 'Smyth', 'email': 'johnsmith@email.com' }) score = scorer.score(rec_a, rec_b) print(f"Combined similarity score: {score:.3f}") ``` -------------------------------- ### Create Single Column Index with ColumnsIndex Source: https://context7.com/pckhoi/datamatch/llms.txt Use ColumnsIndex with a single column name to create buckets based on identical values in that column. This is useful for reducing comparisons by only matching records within the same category. ```python import pandas as pd from datamatch import ThresholdMatcher, ColumnsIndex, StringSimilarity df = pd.DataFrame({ 'id': [1, 2, 3, 4, 5], 'name': ['John', 'Jane', 'Jack', 'Jill', 'James'], 'state': ['CA', 'NY', 'CA', 'NY', 'CA'], 'year': [2020, 2020, 2021, 2020, 2020] }).set_index('id') # Single column index - only compare records from the same state matcher1 = ThresholdMatcher( index=ColumnsIndex('state'), scorer={'name': StringSimilarity()}, dfa=df ) ``` -------------------------------- ### Combine Indices with MultiIndex (OR Logic) Source: https://context7.com/pckhoi/datamatch/llms.txt Use MultiIndex with `combine_keys=False` (default) to implement OR logic, concatenating keys from multiple indices. Records are matched if they satisfy the condition of any of the combined indices. ```python import pandas as pd from datamatch import ThresholdMatcher, MultiIndex, ColumnsIndex, StringSimilarity df = pd.DataFrame({ 'id': [1, 2, 3, 4], 'name': ['John', 'Jane', 'Jack', 'John'], 'dept': ['HR', 'IT', 'HR', 'IT'], 'level': ['senior', 'junior', 'junior', 'senior'] }).set_index('id') # OR mode: match if either dept OR level is the same matcher_or = ThresholdMatcher( index=MultiIndex([ ColumnsIndex('dept'), ColumnsIndex('level') ], combine_keys=False), # OR logic (default) scorer={'name': StringSimilarity()}, dfa=df ) ``` -------------------------------- ### Calculate Jaro-Winkler Similarity for Names Source: https://context7.com/pckhoi/datamatch/llms.txt Employ JaroWinklerSimilarity for string comparison, which gives extra weight to common prefixes. This is particularly effective for matching names and similar strings where prefix agreement is important. ```python from datamatch import JaroWinklerSimilarity # Default prefix weight of 0.1 sim = JaroWinklerSimilarity() score1 = sim.sim('John', 'Jon') print(f"John vs Jon: {score1:.3f}") # High score - same prefix score2 = sim.sim('John', 'Joan') print(f"John vs Joan: {score2:.3f}") # High score - similar prefix score3 = sim.sim('Smith', 'Smyth') print(f"Smith vs Smyth: {score3:.3f}") # High score # Custom prefix weight for more prefix emphasis sim_heavy = JaroWinklerSimilarity(prefix_weight=0.2) score4 = sim_heavy.sim('Robert', 'Roberto') print(f"Robert vs Roberto (heavy prefix): {score4:.3f}") ``` -------------------------------- ### Find Potential Duplicates Source: https://context7.com/pckhoi/datamatch/llms.txt Identify clusters of potential duplicates within a single dataset using a threshold. ```python clusters = matcher.get_index_clusters_within_thresholds(lower_bound=0.7) print(f"Duplicate clusters: {clusters}") ``` -------------------------------- ### SimSumScorer Source: https://context7.com/pckhoi/datamatch/llms.txt Combines similarity scores from multiple fields using a root-mean-square calculation. ```APIDOC ## SimSumScorer - Default Scorer `SimSumScorer` combines similarity scores from multiple fields using a root-mean-square calculation. ### Method Initialization takes a dictionary of field names to similarity scorers. ### Parameters #### Initialization Parameters - **scorers** (dict) - Required - A dictionary where keys are field names (strings) and values are similarity scorer objects. ### Method `score(record_a, record_b)` ### Parameters #### Method Parameters - **record_a** (pd.Series) - Required - The first record (Pandas Series). - **record_b** (pd.Series) - Required - The second record (Pandas Series). ### Response #### Success Response (200) - **score** (float) - The combined similarity score, calculated as the root-mean-square of individual field scores. ### Request Example ```python import pandas as pd from datamatch import SimSumScorer, StringSimilarity, JaroWinklerSimilarity scorer = SimSumScorer({ 'first_name': JaroWinklerSimilarity(), 'last_name': StringSimilarity(), 'email': StringSimilarity() }) rec_a = pd.Series({ 'first_name': 'John', 'last_name': 'Smith', 'email': 'john.smith@email.com' }) rec_b = pd.Series({ 'first_name': 'Jon', 'last_name': 'Smyth', 'email': 'johnsmith@email.com' }) score = scorer.score(rec_a, rec_b) print(f"Combined similarity score: {score:.3f}") ``` ### Response Example ``` Combined similarity score: 0.789 ``` ``` -------------------------------- ### Compare Dates with DateSimilarity Source: https://context7.com/pckhoi/datamatch/llms.txt Use DateSimilarity to calculate the similarity between two dates, considering a maximum allowed day difference and handling potential month/day swaps. This is useful for matching records with approximate or potentially mistyped dates. ```python from datetime import datetime from datamatch import DateSimilarity # Default max difference of 30 days sim = DateSimilarity(d_max=30) date1 = datetime(2020, 1, 15) date2 = datetime(2020, 1, 20) score1 = sim.sim(date1, date2) print(f"5 days apart: {score1:.3f}") # ~0.833 (1 - 5/30) date3 = datetime(2020, 1, 15) date4 = datetime(2020, 2, 15) score2 = sim.sim(date3, date4) print(f"31 days apart: {score2:.3f}") # 0.0 (> d_max) # Month/day swap detection date5 = datetime(2020, 3, 5) date6 = datetime(2020, 5, 3) # Month and day swapped score3 = sim.sim(date5, date6) print(f"Swapped month/day: {score3:.3f}") # 0.5 (detected as typo) # Custom max difference sim_strict = DateSimilarity(d_max=7) # Only 7 days tolerance score4 = sim_strict.sim(date1, date2) print(f"5 days apart (strict): {score4:.3f}") # ~0.286 ``` -------------------------------- ### Aggregate Scores with MaxScorer and MinScorer Source: https://context7.com/pckhoi/datamatch/llms.txt Combines multiple scorers to return either the maximum or minimum score, useful for conditional logic. ```python import pandas as pd from datamatch import MaxScorer, MinScorer, AbsoluteScorer, SimSumScorer, StringSimilarity # AbsoluteScorer returns a fixed score if column values match exactly # MaxScorer picks the higher score between exact match and similarity scorer = MaxScorer([ AbsoluteScorer('employee_id', score=1.0, ignore_key_error=True), SimSumScorer({'name': StringSimilarity()}) ]) rec_a = pd.Series({'employee_id': 'E001', 'name': 'John Smith'}) rec_b = pd.Series({'employee_id': 'E001', 'name': 'Jon Smyth'}) # Returns 1.0 because employee_id matches exactly score = scorer.score(rec_a, rec_b) print(f"Score with matching ID: {score:.3f}") rec_c = pd.Series({'employee_id': 'E002', 'name': 'Jon Smyth'}) # Falls back to name similarity since IDs don't match score2 = scorer.score(rec_a, rec_c) print(f"Score with different ID: {score2:.3f}") ``` -------------------------------- ### Compute Relative Numerical Similarity Source: https://context7.com/pckhoi/datamatch/llms.txt Calculates similarity based on percentage difference, allowing tolerance to scale with the magnitude of the values. ```python from datamatch import RelativeNumericalSimilarity # Maximum 10% difference sim = RelativeNumericalSimilarity(pc_max=10) score1 = sim.sim(100, 105) print(f"100 vs 105 (5% diff): {score1:.3f}") # 0.5 score2 = sim.sim(1000, 1050) print(f"1000 vs 1050 (5% diff): {score2:.3f}") # 0.5 score3 = sim.sim(100, 115) print(f"100 vs 115 (15% diff): {score3:.3f}") # 0.0 (> 10%) # Compare salaries with 20% tolerance salary_sim = RelativeNumericalSimilarity(pc_max=20) print(f"50000 vs 55000: {salary_sim.sim(50000, 55000):.3f}") ``` -------------------------------- ### RelativeNumericalSimilarity Source: https://context7.com/pckhoi/datamatch/llms.txt Computes similarity based on percentage difference, useful when tolerance should scale with value size. ```APIDOC ## RelativeNumericalSimilarity - Number Comparison by Percentage `RelativeNumericalSimilarity` computes similarity based on percentage difference, useful when tolerance should scale with value size. ### Method Initialization takes `pc_max` as a parameter. ### Parameters #### Initialization Parameters - **pc_max** (number) - Required - The maximum allowed percentage difference for a score of 0.0. Scores are calculated as `max(0, 1 - abs(num1 - num2) / max(num1, num2) / (pc_max / 100.0))`. ### Method `sim(num1, num2)` ### Parameters #### Method Parameters - **num1** (number) - Required - The first number. - **num2** (number) - Required - The second number. ### Response #### Success Response (200) - **score** (float) - The similarity score between 0.0 and 1.0. ### Request Example ```python from datamatch import RelativeNumericalSimilarity # Maximum 10% difference sim = RelativeNumericalSimilarity(pc_max=10) score1 = sim.sim(100, 105) print(f"100 vs 105 (5% diff): {score1:.3f}") score2 = sim.sim(1000, 1050) print(f"1000 vs 1050 (5% diff): {score2:.3f}") score3 = sim.sim(100, 115) print(f"100 vs 115 (15% diff): {score3:.3f}") # Compare salaries with 20% tolerance salary_sim = RelativeNumericalSimilarity(pc_max=20) print(f"50000 vs 55000: {salary_sim.sim(50000, 55000):.3f}") ``` ### Response Example ``` 100 vs 105 (5% diff): 0.500 1000 vs 1050 (5% diff): 0.500 100 vs 115 (15% diff): 0.000 50000 vs 55000: 0.500 ``` ``` -------------------------------- ### AlterScorer Source: https://context7.com/pckhoi/datamatch/llms.txt Wraps another scorer and modifies the score when specific conditions are met. ```APIDOC ## AlterScorer - Modify Scores Conditionally `AlterScorer` wraps another scorer and modifies the score when specific conditions are met. ### Method Initialization takes a base scorer, a Pandas Series for values, and an alteration function. ### Parameters #### Initialization Parameters - **scorer** (object) - Required - The base scorer object to wrap. - **values** (pd.Series) - Required - A Pandas Series where the index corresponds to the record's index and values are used for conditional logic. - **alter** (function) - Required - A function that takes the original score and returns the modified score. It should accept one argument (the score) and return a float. ### Method `score(record_a, record_b)` ### Parameters #### Method Parameters - **record_a** (pd.Series) - Required - The first record (Pandas Series). Its index must exist in the `values` Series. - **record_b** (pd.Series) - Required - The second record (Pandas Series). Its index must exist in the `values` Series. ### Response #### Success Response (200) - **score** (float) - The potentially modified similarity score. ### Request Example ```python import pandas as pd from datamatch import AlterScorer, SimSumScorer, StringSimilarity # Create base scorer base_scorer = SimSumScorer({'name': StringSimilarity()}) # Create series mapping indices to departments departments = pd.Series({ 1: 'Engineering', 2: 'Engineering', 3: 'Marketing', 4: 'Marketing' }) # Boost score by 10% when departments match alter_func = lambda score: min(1.0, score * 1.1) # Boost but cap at 1.0 scorer = AlterScorer( scorer=base_scorer, values=departments, alter=alter_func ) rec_a = pd.Series({'name': 'John'}, name=1) # Engineering rec_b = pd.Series({'name': 'Jon'}, name=2) # Engineering score = scorer.score(rec_a, rec_b) print(f"Score with department boost: {score:.3f}") ``` ### Response Example ``` Score with department boost: 0.825 ``` ``` -------------------------------- ### Compute Absolute Numerical Similarity Source: https://context7.com/pckhoi/datamatch/llms.txt Calculates similarity based on the absolute difference between two numbers, capped by a maximum tolerance. ```python from datamatch import AbsoluteNumericalSimilarity # Maximum absolute difference of 10 sim = AbsoluteNumericalSimilarity(d_max=10) score1 = sim.sim(100, 105) print(f"100 vs 105: {score1:.3f}") # 0.5 (1 - 5/10) score2 = sim.sim(100, 100) print(f"100 vs 100: {score2:.3f}") # 1.0 score3 = sim.sim(100, 115) print(f"100 vs 115: {score3:.3f}") # 0.0 (difference > d_max) # Use for age matching with 2 year tolerance age_sim = AbsoluteNumericalSimilarity(d_max=2) print(f"Age 30 vs 31: {age_sim.sim(30, 31):.3f}") # 0.5 ``` -------------------------------- ### Calculate String Similarity using Levenshtein Distance Source: https://context7.com/pckhoi/datamatch/llms.txt Use StringSimilarity to compute the Levenshtein distance ratio between two strings, returning a score between 0 and 1. This metric is suitable for general string comparison and handles Unicode characters. ```python from datamatch import StringSimilarity sim = StringSimilarity() # Compare strings - returns value between 0 and 1 score1 = sim.sim('hello', 'hallo') print(f"hello vs hallo: {score1:.3f}") # ~0.8 score2 = sim.sim('python', 'python') print(f"python vs python: {score2:.3f}") # 1.0 score3 = sim.sim('abc', 'xyz') print(f"abc vs xyz: {score3:.3f}") # 0.0 # Handles unicode via unidecode score4 = sim.sim('cafe', 'caf\u00e9') print(f"cafe vs cafe: {score4:.3f}") # 1.0 ``` -------------------------------- ### Modify Scores with AlterScorer Source: https://context7.com/pckhoi/datamatch/llms.txt Wraps a base scorer to apply custom modifications to the resulting score based on external conditions. ```python import pandas as pd from datamatch import AlterScorer, SimSumScorer, StringSimilarity # Create base scorer base_scorer = SimSumScorer({'name': StringSimilarity()}) # Create series mapping indices to departments departments = pd.Series({ 1: 'Engineering', 2: 'Engineering', 3: 'Marketing', 4: 'Marketing' }) # Boost score by 10% when departments match scorer = AlterScorer( scorer=base_scorer, values=departments, alter=lambda score: min(1.0, score * 1.1) # Boost but cap at 1.0 ) rec_a = pd.Series({'name': 'John'}, name=1) # Engineering rec_b = pd.Series({'name': 'Jon'}, name=2) # Engineering score = scorer.score(rec_a, rec_b) print(f"Score with department boost: {score:.3f}") ``` -------------------------------- ### AbsoluteNumericalSimilarity Source: https://context7.com/pckhoi/datamatch/llms.txt Computes similarity based on the absolute difference between numbers with a maximum tolerance. ```APIDOC ## AbsoluteNumericalSimilarity - Number Comparison by Absolute Difference `AbsoluteNumericalSimilarity` computes similarity based on the absolute difference between numbers with a maximum tolerance. ### Method Initialization takes `d_max` as a parameter. ### Parameters #### Initialization Parameters - **d_max** (number) - Required - The maximum allowed absolute difference for a score of 0.0. Scores are calculated as `max(0, 1 - abs(num1 - num2) / d_max)`. ### Method `sim(num1, num2)` ### Parameters #### Method Parameters - **num1** (number) - Required - The first number. - **num2** (number) - Required - The second number. ### Response #### Success Response (200) - **score** (float) - The similarity score between 0.0 and 1.0. ### Request Example ```python from datamatch import AbsoluteNumericalSimilarity # Maximum absolute difference of 10 sim = AbsoluteNumericalSimilarity(d_max=10) score1 = sim.sim(100, 105) print(f"100 vs 105: {score1:.3f}") score2 = sim.sim(100, 100) print(f"100 vs 100: {score2:.3f}") score3 = sim.sim(100, 115) print(f"100 vs 115: {score3:.3f}") # Use for age matching with 2 year tolerance age_sim = AbsoluteNumericalSimilarity(d_max=2) print(f"Age 30 vs 31: {age_sim.sim(30, 31):.3f}") ``` ### Response Example ``` 100 vs 105: 0.500 100 vs 100: 1.000 100 vs 115: 0.000 Age 30 vs 31: 0.500 ``` ``` -------------------------------- ### MaxScorer and MinScorer Source: https://context7.com/pckhoi/datamatch/llms.txt Aggregate scorers that return the maximum or minimum score from multiple child scorers. ```APIDOC ## MaxScorer and MinScorer - Aggregate Scorers `MaxScorer` returns the maximum score from multiple child scorers, while `MinScorer` returns the minimum. Useful with `AbsoluteScorer` for conditional scoring. ### Method Initialization takes a list of scorer objects. ### Parameters #### Initialization Parameters - **scorers** (list) - Required - A list of scorer objects. ### Method `score(record_a, record_b)` ### Parameters #### Method Parameters - **record_a** (pd.Series) - Required - The first record (Pandas Series). - **record_b** (pd.Series) - Required - The second record (Pandas Series). ### Response #### Success Response (200) - **score** (float) - The aggregated score (maximum for `MaxScorer`, minimum for `MinScorer`). ### Request Example ```python import pandas as pd from datamatch import MaxScorer, MinScorer, AbsoluteScorer, SimSumScorer, StringSimilarity # AbsoluteScorer returns a fixed score if column values match exactly # MaxScorer picks the higher score between exact match and similarity scorer = MaxScorer([ AbsoluteScorer('employee_id', score=1.0, ignore_key_error=True), SimSumScorer({'name': StringSimilarity()}) ]) rec_a = pd.Series({'employee_id': 'E001', 'name': 'John Smith'}) rec_b = pd.Series({'employee_id': 'E001', 'name': 'Jon Smyth'}) # Returns 1.0 because employee_id matches exactly score = scorer.score(rec_a, rec_b) print(f"Score with matching ID: {score:.3f}") rec_c = pd.Series({'employee_id': 'E002', 'name': 'Jon Smyth'}) # Falls back to name similarity since IDs don't match score2 = scorer.score(rec_a, rec_c) print(f"Score with different ID: {score2:.3f}") ``` ### Response Example ``` Score with matching ID: 1.000 Score with different ID: 0.750 ``` ``` -------------------------------- ### Filter Pairs with DissimilarFilter Source: https://context7.com/pckhoi/datamatch/llms.txt Excludes record pairs that share the same value for a specific field, preventing false positives. ```python import pandas as pd from datamatch import ThresholdMatcher, NoopIndex, StringSimilarity, DissimilarFilter # Employee dataset where same employee_id means NOT a duplicate df = pd.DataFrame({ 'id': [1, 2, 3, 4], 'employee_id': ['E001', 'E001', 'E002', 'E003'], 'name': ['John Smith', 'John Smith', 'Jane Doe', 'Janet Doe'] }).set_index('id') # Filter out pairs with same employee_id (they're the same person, not duplicates) matcher = ThresholdMatcher( index=NoopIndex(), scorer={'name': StringSimilarity()}, dfa=df, filters=[DissimilarFilter('employee_id')] # Exclude if employee_id matches ) ``` -------------------------------- ### DissimilarFilter Source: https://context7.com/pckhoi/datamatch/llms.txt Eliminates pairs that have the same value for a specified field, useful when same values indicate non-matches. ```APIDOC ## DissimilarFilter - Exclude Matching Values `DissimilarFilter` eliminates pairs that have the same value for a specified field, useful when same values indicate non-matches. ### Method Initialization takes the field name to filter on. ### Parameters #### Initialization Parameters - **field** (string) - Required - The name of the field to check for dissimilar values. ### Usage within ThresholdMatcher Filters are passed as a list to the `filters` parameter of `ThresholdMatcher`. ### Request Example ```python import pandas as pd from datamatch import ThresholdMatcher, NoopIndex, StringSimilarity, DissimilarFilter # Employee dataset where same employee_id means NOT a duplicate df = pd.DataFrame({ 'id': [1, 2, 3, 4], 'employee_id': ['E001', 'E001', 'E002', 'E003'], 'name': ['John Smith', 'John Smith', 'Jane Doe', 'Janet Doe'] }).set_index('id') # Filter out pairs with same employee_id (they're the same person, not duplicates) matcher = ThresholdMatcher( index=NoopIndex(), scorer={'name': StringSimilarity()}, dfa=df, filters=[DissimilarFilter('employee_id')] # Exclude if employee_id matches ) # The matcher will only consider pairs where employee_id is different. # In this example, pairs (1, 2) would be excluded by the DissimilarFilter # because they share the same 'employee_id'. ``` ``` -------------------------------- ### Filter Overlapping Time Ranges Source: https://context7.com/pckhoi/datamatch/llms.txt Use NonOverlappingFilter to exclude record pairs that have overlapping date ranges. ```python import pandas as pd from datetime import datetime from datamatch import ThresholdMatcher, NoopIndex, StringSimilarity, NonOverlappingFilter # Employees with employment periods df = pd.DataFrame({ 'id': [1, 2, 3, 4], 'name': ['John Smith', 'John Smith', 'John Smith', 'Jane Doe'], 'start_date': [ datetime(2020, 1, 1), datetime(2021, 1, 1), datetime(2020, 6, 1), # Overlaps with id=1 datetime(2020, 1, 1) ], 'end_date': [ datetime(2020, 12, 31), datetime(2021, 12, 31), datetime(2020, 12, 31), # Overlaps with id=1 datetime(2020, 12, 31) ] }).set_index('id') # Only match records with non-overlapping date ranges matcher = ThresholdMatcher( index=NoopIndex(), scorer={'name': StringSimilarity()}, dfa=df, filters=[NonOverlappingFilter('start_date', 'end_date')] ) # Won't match id=1 with id=3 because their ranges overlap clusters = matcher.get_index_clusters_within_thresholds(lower_bound=0.8) print(f"Non-overlapping matches: {clusters}") ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.