TIF_E41253310/Backend/app/utils/standardization.py

194 lines
5.5 KiB
Python

"""
Standarisasi Kolom Module
Memetakan kolom dari berbagai tahun ke kolom standar
"""
import pandas as pd
import json
from pathlib import Path
from typing import Dict, List, Optional
class ColumnStandardizer:
"""
Kelas untuk menstandarisasi kolom dari berbagai file Excel
dengan struktur kolom yang berbeda-beda
"""
def __init__(self, mapping_file: str = None):
"""
Args:
mapping_file: Path ke file JSON mapping kolom
"""
if mapping_file is None:
# Default path
mapping_file = Path(__file__).parent.parent / "column_mapping.json"
self.mapping_file = Path(mapping_file)
self.mappings = self._load_mappings()
def _load_mappings(self) -> Dict:
"""Load mapping dari file JSON"""
if not self.mapping_file.exists():
raise FileNotFoundError(f"Mapping file tidak ditemukan: {self.mapping_file}")
with open(self.mapping_file, 'r', encoding='utf-8') as f:
return json.load(f)
def get_mapping(self, year: str) -> Dict:
"""
Ambil mapping untuk tahun tertentu
Args:
year: Tahun data (2022, 2023, 2024)
Returns:
Dictionary dengan mapping kolom
"""
if year not in self.mappings:
raise ValueError(f"Mapping untuk tahun {year} tidak ditemukan. "
f"Tahun yang tersedia: {list(self.mappings.keys())}")
return self.mappings[year]
def detect_year(self, df: pd.DataFrame, filename: str = None) -> Optional[str]:
"""
Deteksi tahun dari DataFrame atau filename
Args:
df: DataFrame untuk dicek kolomnya
filename: Nama file (opsional)
Returns:
Tahun yang terdeteksi atau None
"""
# Cek dari filename
if filename:
for year in self.mappings.keys():
if year in filename:
return year
# Cek dari kolom yang tersedia
available_years = []
for year, mapping in self.mappings.items():
match_count = sum(1 for col in mapping.values() if col in df.columns)
if match_count >= 2: # Minimal 2 kolom cocok
available_years.append((year, match_count))
if available_years:
# Pilih tahun dengan match terbanyak
return max(available_years, key=lambda x: x[1])[0]
return None
def standardize(self, df: pd.DataFrame, year: str = None, filename: str = None) -> pd.DataFrame:
"""
Standarisasi kolom DataFrame
Args:
df: DataFrame asli
year: Tahun data (auto-detect jika None)
filename: Nama file (opsional, untuk auto-detect)
Returns:
DataFrame dengan kolom standar
"""
# Deteksi tahun jika tidak specified
if year is None:
year = self.detect_year(df, filename)
if year is None:
raise ValueError("Tidak dapat mendeteksi tahun data. "
f"Pastikan kolom sesuai dengan mapping yang tersedia.")
# Ambil mapping
mapping = self.get_mapping(year)
# Buat DataFrame baru dengan kolom standar
result = pd.DataFrame()
for target_col, source_col in mapping.items():
if source_col in df.columns:
result[target_col] = df[source_col]
else:
result[target_col] = None
return result
def standardize_multiple(self, dfs: List[pd.DataFrame],
years: List[str] = None,
filenames: List[str] = None) -> List[pd.DataFrame]:
"""
Standarisasi multiple DataFrame sekaligus
Args:
dfs: List DataFrame
years: List tahun (auto-detect jika None)
filenames: List nama file (opsional)
Returns:
List DataFrame yang sudah distandarisasi
"""
results = []
for i, df in enumerate(dfs):
year = years[i] if years else None
filename = filenames[i] if filenames else None
standardized = self.standardize(df, year, filename)
results.append(standardized)
return results
def merge_datasets(dfs: List[pd.DataFrame]) -> pd.DataFrame:
"""
Gabungkan multiple DataFrame menjadi satu
Args:
dfs: List DataFrame
Returns:
DataFrame gabungan
"""
return pd.concat(dfs, ignore_index=True)
def clean_data(df: pd.DataFrame) -> pd.DataFrame:
"""
Basic data cleaning
Args:
df: DataFrame
Returns:
DataFrame yang sudah dibersihkan
"""
result = df.copy()
# Hapus baris dengan semua nilai kosong
result = result.dropna(how='all')
# Hapus duplikat
result = result.drop_duplicates()
# Isi nilai kosong dengan string kosong
result = result.fillna('')
return result
if __name__ == "__main__":
# Contoh penggunaan
standardizer = ColumnStandardizer()
# Sample data 2024
sample_2024 = pd.DataFrame({
"4. Nama Lengkap / nmmhsmsmh (Gunakan Huruf Besar)": ["Ali", "Budi"],
"9. Apa nama perusahaan/kantor tempat Anda bekerja? f5b": ["Google", "Tokopedia"],
"10. Bila Anda berwiraswasta, apa posisi/jabatan Anda saat ini ? f5c": ["Engineer", "Analyst"]
})
# Standarisasi
standardized = standardizer.standardize(sample_2024, year="2024")
print("Data Standarisasi:")
print(standardized)