Datavision / backend /core /multi_dataset_engine.py
DataVision CI/CD Bot
release: clean production build for HuggingFace Space
09801ca
Raw
History Blame Contribute Delete
4.47 kB
import pandas as pd
from typing import List, Dict, Any, Tuple
import logging
from utils.paths import get_user_paths
logger = logging.getLogger(__name__)
class MultiDatasetEngine:
"""Intelligent engine for analyzing and joining multiple datasets"""
@staticmethod
def infer_joins(df1: pd.DataFrame, df2: pd.DataFrame, df1_name: str, df2_name: str) -> List[Dict[str, Any]]:
"""
Intelligently infer possible join keys between two dataframes based on column names and content.
Returns a list of suggested joins ranked by confidence.
"""
suggestions = []
cols1 = set(df1.columns)
cols2 = set(df2.columns)
# 1. Exact match on ID-like columns
id_keywords = ['id', 'uuid', 'key']
exact_matches = cols1.intersection(cols2)
for col in exact_matches:
if any(kw in col.lower() for kw in id_keywords):
# Verify type compatibility
if df1[col].dtype == df2[col].dtype:
# Calculate overlap
overlap = len(set(df1[col]).intersection(set(df2[col])))
if overlap > 0:
confidence = 0.95 if overlap > len(df1) * 0.1 or overlap > len(df2) * 0.1 else 0.7
suggestions.append({
"left_key": col,
"right_key": col,
"confidence": confidence,
"reason": f"Exact match on ID column '{col}' with data overlap."
})
# 2. Heuristic match (e.g. 'customer_id' in df1, 'id' in df2 where df2 is 'customers')
for col1 in cols1:
for col2 in cols2:
# If col1 is like 'table2_id' and col2 is 'id'
if col1.lower() == f"{df2_name.lower().replace('.csv', '')}_id" and col2.lower() == 'id':
overlap = len(set(df1[col1]).intersection(set(df2[col2])))
if overlap > 0:
suggestions.append({
"left_key": col1,
"right_key": col2,
"confidence": 0.85,
"reason": f"Inferred foreign key relationship '{col1}' -> '{col2}'."
})
# If col2 is like 'table1_id' and col1 is 'id'
elif col2.lower() == f"{df1_name.lower().replace('.csv', '')}_id" and col1.lower() == 'id':
overlap = len(set(df1[col1]).intersection(set(df2[col2])))
if overlap > 0:
suggestions.append({
"left_key": col1,
"right_key": col2,
"confidence": 0.85,
"reason": f"Inferred foreign key relationship '{col1}' <- '{col2}'."
})
# Sort by confidence descending
suggestions.sort(key=lambda x: x['confidence'], reverse=True)
return suggestions
@staticmethod
def join_datasets(
df1: pd.DataFrame,
df2: pd.DataFrame,
left_on: str,
right_on: str,
how: str = 'left'
) -> pd.DataFrame:
"""
Execute the join between two datasets.
Handles duplicates and renaming intelligently.
"""
# Ensure compatible types for joining
if df1[left_on].dtype != df2[right_on].dtype:
try:
# Attempt to coerce to string for joining if types mismatch
df1[left_on] = df1[left_on].astype(str)
df2[right_on] = df2[right_on].astype(str)
except Exception as e:
logger.warning(f"Could not coerce types for join: {e}")
# Perform merge
merged = pd.merge(df1, df2, left_on=left_on, right_on=right_on, how=how, suffixes=('_left', '_right'))
# If right_on is different from left_on, we might have redundant columns, but pandas merge handles it.
# If they are different names, both are kept. We can drop the right_on if it's redundant.
if left_on != right_on and right_on in merged.columns:
# Only drop if the values are identical (as in inner/left join)
if how in ['left', 'inner']:
merged = merged.drop(columns=[right_on])
return merged