+ Provides executable leakage controls, sparse encoding, and validation.
- It falsely flags C004's login as missing and contradicts its filtering.
a Senior Data Science Architect and Lead Business Analyst.
| Category | Development › Data & databases |
|---|---|
| Tags | AnalyzingDraftingDeveloperSpreadsheetCode |
I want you to act as a Senior Data Science Architect and Lead Business Analyst. I am uploading a CSV file that contains raw data. Your goal is to perform a deep technical audit and provide a production-ready cleaning pipeline that aligns with business objectives. Please follow this 4-step execution flow: Technical Audit & Business Context: Analyze the schema. Identify inconsistencies, missing values, and Data Smells. Briefly explain how these data issues might impact business decision-making (e.g., Inconsistent dates may lead to incorrect monthly trend analysis). Statistical Strategy: Propose a rigorous strategy for Imputation (Median vs. Mean), Encoding (One-Hot vs. Label), and Scaling (Standard vs. Robust) based on the audit. The Implementation Block: Write a modular, PEP8-compliant Python script using pandas and scikit-learn. Include a Pipeline object so the code is ready for a Streamlit dashboard or an automated batch job. Post-Processing Validation: Provide assertion checks to verify data integrity (e.g., checking for nulls or memory optimization via down casting). Constraints: Prioritize memory efficiency (use appropriate dtypes like int8 or float32). Ensure zero data leakage if a target variable is present. Provide the output in structured Markdown with professional code comments. I have uploaded the file. Please begin the audit.
This prompt asks the model to act as a senior data science architect and business analyst. It requires structured Markdown with memory efficiency, leakage prevention, and validation assertions.
ChatGPT is the most complete and production-ready. Gemini is detailed but truncated, while [C] was not provided.
+ Provides executable leakage controls, sparse encoding, and validation.
- It falsely flags C004's login as missing and contradicts its filtering.
+ Connects column issues to concrete business impacts.
- The code is truncated and misses C002's absent age.
| Criterion | ChatGPT | Gemini | Leader |
|---|---|---|---|
| Instruction following | 9 | 4 | ChatGPT +125% |
| Accuracy | 7 | 5 | ChatGPT +40% |
| Specificity | 9 | 8 | ChatGPT +13% |
| Structure | 9 | 7 | ChatGPT +29% |
| Right length | 8 | 3 | ChatGPT +167% |
Scored 1–10 by gpt-5.6-sol with model names hidden (2026-09-25). This is an AI review, not a measurement.
We gave three models the same input and copied their answers unedited. Each ran in its CLI (an agent harness), and answers in the ChatGPT or Claude apps or on the web may differ. Outputs are in Korean.
[Pasted material] customer_id,signup_date,last_login,age,gender,plan,monthly_fee,region,churned C001,2024-01-15,2026-08-20,34,M,Pro,29900,Seoul,0 C002,01/16/2024,,,F,Basic,9900,seoul,1 C003,2024-1-17,2026-08-01,29,Male,Pro,29900,Busan,0 C004,2024-01-18,2026-07-11,,F,Basic,,Incheon, C005,2024-01-19,2026-08-22,41,M,Premium,49900,Seoul ,0 C006,2024-01-20,2025-11-02,-5,F,Basic,9900,Daegu,1 C007,2024/01/21,2026-08-19,38,M,Pro,29900,Seoul,0
분석 대상은 7건이며, 실제 모델링에 사용할 수 있는 타깃 데이터는 churned가 결측인 C004를 제외한 6건입니다. 표본 수가 매우 작으므로 아래 통계는 운영 규칙 수립을 위한 탐색 결과로만 사용해야 합니다.
| 컬럼 | 발견 사항 | 비즈니스 영향 |
|---|---|---|
customer_id |
중복 없음. 식별자 컬럼 | 모델 입력에 사용하면 과적합 및 개인정보 노출 위험 |
signup_date |
2024-01-15, 01/16/2024, 2024/01/21 등 형식 혼재 |
월별 가입 추이와 코호트 분석 오류 |
last_login |
C002, C004 결측 | 휴면·이탈 위험도 계산 왜곡 |
age |
C004 결측, C006은 -5 |
고객 세그먼트 및 연령별 이탈 분석 오류 |
gender |
M, Male 혼재 |
성별 집계가 서로 다른 고객으로 분리될 수 있음 |
plan |
현재 결측 없음 | 향후 신규 플랜 유입 가능성을 고려해야 함 |
monthly_fee |
C004 결측 | 매출, ARPU, 플랜별 수익성 분석 왜곡 |
region |
Seoul, seoul, Seoul 혼재 |
지역별 매출·이탈률 집계 오류 |
churned |
C004 결측 | 타깃이 없는 행은 지도학습에서 제외해야 함 |
| 전체 | C002와 C004에 다수 결측 집중 | 특정 데이터 수집 채널 또는 입력 프로세스 문제 가능성 |
추가 데이터 스멜은 다음과 같습니다.
age=-5는 결측 또는 입력 오류로 처리해야 합니다.monthly_fee는 원화 정수형으로 보이며, 모델링 전에 단위와 통화 기준을 명시해야 합니다.last_login 결측은 단순 누락이 아니라 실제 미로그인 상태일 수도 있습니다. 따라서 결측값 자체가 이탈 신호일 가능성이 있습니다.last_login이 예측 시점 이후의 정보가 아닌지 반드시 확인해야 합니다.age: 중앙값 대체monthly_fee: 중앙값 대체last_login 파생 변수: 중앙값 대체 + 결측 여부 indicator 추가churned: 대체하지 않고 해당 행을 학습 데이터에서 제외gender, plan, region: One-Hot Encodinghandle_unknown="ignore"를 적용합니다.RobustScaler 사용age, monthly_fee, 날짜 파생 변수는 이상치 또는 비대칭 분포가 발생할 수 있습니다.StandardScaler보다 중앙값과 사분위 범위를 사용하는 RobustScaler가 적합합니다.churned를 먼저 분리합니다.fit()합니다.transform()만 수행합니다."""
Customer churn preprocessing pipeline.
Expected input columns:
customer_id, signup_date, last_login, age, gender,
plan, monthly_fee, region, churned
"""
from __future__ import annotations
from typing import Any
import numpy as np
import pandas as pd
from scipy import sparse
from sklearn.base import BaseEstimator, TransformerMixin
from sklearn.compose import ColumnTransformer
from sklearn.impute import SimpleImputer
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import OneHotEncoder, RobustScaler
NUMERIC_COLUMNS = [
"age",
"monthly_fee",
"signup_year",
"signup_month",
"signup_dayofweek",
"last_login_year",
"last_login_month",
"last_login_dayofweek",
"days_to_last_login",
]
CATEGORICAL_COLUMNS = [
"gender",
"plan",
"region",
]
class BusinessCleaner(BaseEstimator, TransformerMixin):
"""Apply business rules and create model-ready date features."""
DATE_COLUMNS = ("signup_date", "last_login")
@staticmethod
def _parse_date(series: pd.Series) -> pd.Series:
"""Parse mixed date formats while converting invalid dates to NaT."""
try:
return pd.to_datetime(
series,
format="mixed",
errors="coerce",
)
except TypeError:
# Compatibility with older pandas versions.
return pd.to_datetime(series, errors="coerce")
def fit(
self,
X: pd.DataFrame,
y: pd.Series | None = None,
) -> "BusinessCleaner":
"""No statistics are learned here, preventing target leakage."""
return self
def transform(self, X: pd.DataFrame) -> pd.DataFrame:
"""Clean raw records and generate date-derived features."""
data = X.copy()
# Identifier is not a predictive feature.
data = data.drop(columns=["customer_id"], errors="ignore")
# Normalize categorical values.
if "gender" in data.columns:
data["gender"] = (
data["gender"]
.astype("string")
.str.strip()
.str.upper()
.replace({"MALE": "M", "FEMALE": "F"})
)
if "plan" in data.columns:
data["plan"] = (
data["plan"]
.astype("string")
.str.strip()
.str.title()
)
if "region" in data.columns:
data["region"] = (
data["region"]
.astype("string")
.str.strip()
.str.lower()
.str.title()
)
# Convert numeric columns and invalidate impossible values.
data["age"] = pd.to_numeric(data["age"], errors="coerce")
data.loc[~data["age"].between(0, 120), "age"] = np.nan
data["monthly_fee"] = pd.to_numeric(
data["monthly_fee"],
errors="coerce",
)
data.loc[data["monthly_fee"] < 0, "monthly_fee"] = np.nan
# Create numeric date features and remove raw date strings.
signup = self._parse_date(data["signup_date"])
last_login = self._parse_date(data["last_login"])
data["signup_year"] = signup.dt.year
data["signup_month"] = signup.dt.month
data["signup_dayofweek"] = signup.dt.dayofweek
data["last_login_year"] = last_login.dt.year
data["last_login_month"] = last_login.dt.month
data["last_login_dayofweek"] = last_login.dt.dayofweek
data["days_to_last_login"] = (
last_login - signup
).dt.days
data = data.drop(
columns=["signup_date", "last_login"],
errors="ignore",
)
# Use compact numerical types where possible.
for column in NUMERIC_COLUMNS:
if column in data.columns:
data[column] = pd.to_numeric(
data[column],
errors="coerce",
downcast="float",
)
return data
def make_one_hot_encoder() -> OneHotEncoder:
"""Create a version-compatible memory-efficient encoder."""
try:
return OneHotEncoder(
handle_unknown="ignore",
sparse_output=True,
dtype=np.float32,
)
except TypeError:
# Compatibility with scikit-learn versions before 1.2.
return OneHotEncoder(
handle_unknown="ignore",
sparse=True,
dtype=np.float32,
)
def build_preprocessing_pipeline() -> Pipeline:
"""Build the complete leakage-safe preprocessing pipeline."""
numeric_pipeline = Pipeline(
steps=[
(
"imputer",
SimpleImputer(
strategy="median",
add_indicator=True,
),
),
(
"scaler",
RobustScaler(),
),
]
)
categorical_pipeline = Pipeline(
steps=[
(
"imputer",
SimpleImputer(
strategy="most_frequent",
),
),
(
"encoder",
make_one_hot_encoder(),
),
]
)
preprocessor = ColumnTransformer(
transformers=[
(
"numeric",
numeric_pipeline,
NUMERIC_COLUMNS,
),
(
"categorical",
categorical_pipeline,
CATEGORICAL_COLUMNS,
),
],
remainder="drop",
)
return Pipeline(
steps=[
("business_cleaner", BusinessCleaner()),
("preprocessor", preprocessor),
]
)
def validate_raw_target(
target: pd.Series,
) -> pd.Series:
"""Validate and compact the binary target variable."""
target = pd.to_numeric(target, errors="coerce")
# Rows without labels cannot be used for supervised training.
if target.isna().any():
raise ValueError(
"Target contains missing values. "
"Remove unlabeled rows before fitting."
)
invalid_values = ~target.isin([0, 1])
if invalid_values.any():
raise ValueError(
"Target must contain only binary values 0 or 1."
)
return target.astype(np.int8)
def validate_transformed_output(
transformed: Any,
target: pd.Series,
) -> None:
"""Assert core integrity conditions after transformation."""
assert transformed.shape[0] == target.shape[0]
assert transformed.shape[1] > 0
if sparse.issparse(transformed):
assert np.isfinite(transformed.data).all()
else:
assert np.isfinite(transformed).all()
assert target.isna().sum() == 0
assert target.dtype == np.int8
def load_and_prepare_data(
csv_path: str,
) -> tuple[pd.DataFrame, pd.Series]:
"""Load data, separate target, and remove unlabeled records."""
raw = pd.read_csv(csv_path)
required_columns = {
"customer_id",
"signup_date",
"last_login",
"age",
"gender",
"plan",
"monthly_fee",
"region",
"churned",
}
missing_columns = required_columns.difference(raw.columns)
if missing_columns:
raise ValueError(
f"Missing required columns: {sorted(missing_columns)}"
)
target = pd.to_numeric(raw["churned"], errors="coerce")
labeled_mask = target.notna()
X = raw.loc[labeled_mask].drop(columns=["churned"])
y = validate_raw_target(target.loc[labeled_mask])
return X, y
def main() -> None:
"""Example batch-training entry point."""
X, y = load_and_prepare_data("customers.csv")
pipeline = build_preprocessing_pipeline()
# Fit only on X and y; target is never passed into the cleaner.
pipeline.fit(X, y)
transformed = pipeline.transform(X)
validate_transformed_output(transformed, y)
print(f"Rows processed: {transformed.shape[0]}")
print(f"Features generated: {transformed.shape[1]}")
print("Validation passed: no null or non-finite transformed values.")
if __name__ == "__main__":
main()
현재 샘플 기준 예상 처리 결과는 다음과 같습니다.
churned 결측이므로 학습 데이터에서 제외age=-5를 결측으로 변환 후 중앙값 대체age, monthly_fee, last_login 결측을 파이프라인에서 처리M과 Male은 M으로 통합Seoul, seoul, Seoul 은 Seoul로 통합RobustScaler를 통해 이상치 영향이 완화됨float32 sparse matrix를 사용하여 메모리를 절약함실제 운영 전에는 최소한 다음을 추가로 확인해야 합니다.
last_login이 예측 기준일 이후의 정보인지 여부handle_unknown="ignore" 동작 확인현재 데이터는 7건뿐이므로 모델 성능 평가나 통계적 결론을 내리기에는 부족합니다. 이 데이터셋은 우선 데이터 품질 규칙과 파이프라인 검증용 샘플로 사용하는 것이 적절합니다.
| Advanced Text Converter for Large Datasets | |
| AI-powered data extraction and organization tool | |
| AI2sql SQL Model — Query Generator | |
| Backend Architect | |
| base-R |