파이썬 문제를 디버깅하는 기본


저자의 이미지 | 캔버
파이썬 스크립트를 실행하고 즉시 Enter를 누르지 않기를 바랐습니까?
데이터 과학의 디버깅은 단순한 행위가 아닙니다. 그것은 생존 기술입니다. 특히 지저분한 데이터 세트를 다루거나 실제 사람들이 의존하는 예측 모델을 고안 할 때.
이 기사에서는 Doordash 배송 작업의 실제 데이터 세트를 사용하고 가장 중요한 것은 프로처럼 디버깅하는 방법을 사용하여 디버깅의 기본, 특히 데이터 과학 워크 플로우에서 디버깅의 기본 사항을 살펴볼 것입니다.
Doordash 배달 기간 예측 : 우리는 무엇을 다루고 있습니까?
이 데이터 프로젝트에서 Doordash는 데이터 과학 후보자에게 전달 기간을 예측하도록 요청했습니다. 먼저 데이터 세트 정보를 살펴 보겠습니다. 코드는 다음과 같습니다.
출력은 다음과 같습니다.
그들이 배달 기간을 제공하지 않았으므로 여기에서 계산해야합니다. 간단하지만 초보자라면 걱정할 수 없습니다. 어떻게 계산할 수 있는지 봅시다.
import pandas as pd
from datetime import datetime
# Assuming historical_data is your DataFrame
historical_data["created_at"] = pd.to_datetime(historical_data['created_at'])
historical_data["actual_delivery_time"] = pd.to_datetime(historical_data['actual_delivery_time'])
historical_data["actual_total_delivery_duration"] = (historical_data["actual_delivery_time"] - historical_data["created_at"]).dt.total_seconds()
historical_data.head()
다음은 출력의 머리입니다. 당신은 볼 수 있습니다 actual_total_delivery_duration
.
좋아, 이제 우리는 시작할 수 있습니다! 그러나 그 전에는이 데이터 세트의 데이터 정의 언어가 있습니다.
컬럼 historical_data.csv
시간 기능 :
- Market_id : Doordash가 운영되는 도시/지역 (예 : 로스 앤젤레스)은 데이터에 ID로 제공됩니다.
- create_at : UTC의 Timestamp는 소비자가 Doordash에 주문을 제출했을 때. (참고 :이 타임 스탬프는 UTC에 있지만 필요한 경우이 지역의 실제 시간대는 미국/태평양이었습니다).
- 실제_delivery_time : 주문이 소비자에게 전달 될 때 UTC의 타임 스탬프.
저장 기능 :
- Store_id : 주문이 제출 된 식당을 나타내는 ID.
- Store_primary_category : 식당의 요리 카테고리, 예를 들어, 이탈리아, 아시아.
- Order_Protocol : 상점은 많은 모드를 통해 doordash로부터 주문을받을 수 있습니다. 이 필드는 프로토콜을 나타내는 ID를 나타냅니다.
주문 기능 :
- Total_items : 순서대로 총 항목 수.
- 소계 : 제출 된 주문의 총 가치 (센트).
- NUM_DISTINCT_ITEMS : 순서에 포함 된 고유 한 항목의 수.
- min_item_price : 순서대로 비용이 가장 적은 품목의 가격 (센트).
- max_item_price : 순서대로 비용이 가장 높은 품목의 가격 (센트).
시장 기능 :
Doordash는 마켓 플레이스이기 때문에 주문이 배치 될 때 시장 상태에 대한 정보를 가지고 있으며, 이는 배송 시간을 추정하는 데 사용할 수 있습니다. 다음 기능은 당시의 값입니다 created_at
(주문 제출 시간) :
- Total_onshift_dashers : 주문 생성 시점에서 매장에서 10 마일 이내에있는 사용 가능한 대쉬 수.
- Total_busy_dashers : 위의 하위 집합
total_onshift_dashers
현재 주문을하고있는 사람. - Total_outstanding_orders : 현재 처리중인이 주문에서 10 마일 이내의 주문 수.
다른 모델의 예측 :
우리는 사용할 수있는 전달 프로세스의 다양한 단계에 대한 다른 모델의 예측을 가지고 있습니다.
- wotaled_order_place_duration : 식당이 doordash (초)로부터 주문을받는 예상 시간.
- 추정 _store_to_consumer_driving_duration : 상점과 소비자 간의 이동 시간 (초).
좋아요, 시작합시다!
데이터 과학 프로젝트의 일반적인 파이썬 오류
이 섹션에서는 데이터 세트를 읽고 가장 중요한 부분 인 모델링으로 시작하여 데이터 과학 프로젝트 중 하나에서 일반적인 디버깅 오류를 발견합니다.
데이터 세트 읽기 : FileNotFoundError
dtype 경고 및 수정
사례 1 : 파일 찾기 – 클래식
데이터 과학에서 첫 번째 버그는 종종 당신을 맞이합니다. read_csv
. 그리고 인사가 아닙니다. 그 정확한 순간을 함께 한 줄씩 디버깅합시다. 코드는 다음과 같습니다.
import pandas as pd
try:
df = pd.read_csv('Strata Questions/historical_data.csv')
df.head(3)
except FileNotFoundError as e:
import os
print("File not found. Here's where Python is looking:")
print("Working directory:", os.getcwd())
print("Available files:", os.listdir())
raise e
다음은 출력입니다.
당신은 단지 오류를 제기하지 않고 심문합니다. 이것은 코드의 위치와 주변의 내용을 보여줍니다. 파일이 목록에 있지 않은 경우 이제 알 수 있습니다. 추측이 없습니다. 그냥 사실.
경로를 전체로 교체하십시오!
사례 2 : Dtype 오해 – 파이썬은 조용히 잘못된 추측입니다
데이터 세트를로드하지만 무언가가 꺼져 있습니다. 버그는 유형 안에 숨어 있습니다.
# Assuming df is your loaded DataFrame
try:
print("Column Types:\n", df.dtypes)
except Exception as e:
print("Error reading dtypes:", e)
다음은 출력입니다.
사례 3 : 날짜 구문 분석 – 조용한 파괴자
우리는 먼저 전달 기간을 계산해야한다는 것을 발견 했으며이 방법으로 수행했습니다.
try:
# This code was shown earlier to calculate the delivery duration
df["created_at"] = pd.to_datetime(df['created_at'])
df["actual_delivery_time"] = pd.to_datetime(df['actual_delivery_time'])
df["actual_total_delivery_duration"] = (df["actual_delivery_time"] - df["created_at"]).dt.total_seconds()
print("Successfully calculated delivery duration and checked dtypes.")
print("Relevant dtypes:\n", df[['created_at', 'actual_delivery_time', 'actual_total_delivery_duration']].dtypes)
except Exception as e:
print("Error during date processing:", e)
다음은 출력입니다.
좋고 전문적인! 이제 우리는 그 빨간 오류를 피하는데, 이는 우리의 기분을 높이게 될 것입니다. 나는 그들이 당신의 동기를 약화시킬 수 있다는 것을 알고 있습니다.
누락 데이터 처리 : KeyErrors
,,, NaNs
그리고 논리적 함정
일부 버그는 코드가 충돌하지 않습니다. 모델이 왜 쓰레기인지 궁금해 할 때까지 그들은 당신에게 잘못된 결과를 조용히 제공합니다.
이 섹션은 누락 된 데이터를 파헤칩니다. 청소 방법뿐만 아니라 제대로 디버깅하는 방법.
사례 1 : Keyerror – 열이 존재한다고 생각했습니다
다음은 코드입니다.
try:
print(df['store_rating'])
except KeyError as e:
print("Column not found:", e)
print("Here are the available columns:\n", df.columns.tolist())
다음은 출력입니다.
논리 때문에 코드가 깨지지 않았습니다. 가정 때문에 파산했습니다. 그것이 바로 디버깅이 살아있는 곳입니다. 맹목적으로 액세스하기 전에 항상 열을 나열하십시오.
사례 2 : Nan Count – 예상하지 않은 결 측값
당신은 모든 것이 깨끗하다고 생각합니다. 그러나 실제 데이터는 항상 격차를 숨 깁니다. 그들을 확인합시다.
try:
null_counts = df.isnull().sum()
print("Nulls per column:\n", null_counts[null_counts > 0])
except Exception as e:
print("Failed to inspect nulls:", e)
다음은 출력입니다.
이것은 침묵 문제를 해결합니다. 아마도 store_primary_category
수천 행으로 누락되었습니다. 아마도 타임 스탬프가 변환에 실패했을 수도 있습니다 NaT
.
확인하지 않으면 알지 못했을 것입니다. 디버깅 – 모든 가정을 확인합니다.
사례 3 : 논리적 함정 – 실제로 누락되지 않은 누락 된 데이터
하위 운동이 1,000,000보다 큰 곳에서 주문을 필터링하려고한다고 가정 해 봅시다. 그러나 이것은 당신에게 0을줍니다.
try:
filtered = df[df['subtotal'] > 1000000]
print("Rows with subtotal > 1,000,000:", filtered.shape[0])
except Exception as e:
print("Filtering error:", e)
코드 오류가 아닙니다. 로직 오류입니다. 당신은 고 부가가치 주문을 예상했지만 그 임계 값 위에는 존재하지 않을 수도 있습니다. 범위 점검으로 디버깅 :
print("Subtotal range:", df['subtotal'].min(), "to", df['subtotal'].max())
다음은 출력입니다.
Case 4: isna()
≠ Zero가 깨끗하다는 것을 의미하지는 않습니다
설사 isna().sum()
영점을 보여 주면, 공백 또는 ‘없음’과 같은 더러운 데이터가 문자열로있을 수 있습니다. 보다 공격적인 점검을 실행하십시오.
try:
fake_nulls = df[df['store_primary_category'].isin(['', ' ', 'None', None])]
print("Rows with fake missing categories:", fake_nulls.shape[0])
except Exception as e:
print("Fake missing value check failed:", e)
이것은 숨겨진 쓰레기를 잡습니다 isnull()
미스.
기능 엔지니어링 글리치 : TypeErrors
날짜 구문 분석 등
기능 엔지니어링은 새로운 열이 모든 모델을 깨거나 던질 때까지 처음에는 재미있는 것 같습니다. TypeError
미드 파이프 라인. 다음은 전에 화상을 입은 사람처럼 해당 단계를 디버그하는 방법입니다.
사례 1 : 당신은 나눌 수 있다고 생각하지만 당신은 할 수 없습니다.
새로운 기능을 만들어 봅시다. 오류가 발생하면 우리 try-except
블록이 잡을 것입니다.
try:
df['value_per_item'] = df['subtotal'] / df['total_items']
print("value_per_item created successfully")
except Exception as e:
print("Error occurred:", e)
다음은 출력입니다.
오류가 없습니까? 좋은. 그러나 더 자세히 살펴 보겠습니다.
print(df[['subtotal', 'total_items', 'value_per_item']].sample(3))
다음은 출력입니다.
사례 2 : 날짜 구문 분석이 잘못되었습니다
이제, 당신의 변화 dtype
중요하지만 모든 것이 올바르게 이루어 졌다고 생각하면 문제가 지속되면 어떻게해야합니까?
# This is the standard way, but it can fail silently on mixed types
df["created_at"] = pd.to_datetime(df["created_at"])
df["actual_delivery_time"] = pd.to_datetime(df["actual_delivery_time"])
당신은 그것이 괜찮다고 생각할 수도 있지만, 열에 혼합 유형이 있으면 조용히 실패하거나 파이프 라인을 끊을 수 있습니다. 그렇기 때문에 직접 변환하는 대신 강력한 기능을 사용하는 것이 좋습니다.
from datetime import datetime
def parse_date_debug(df, col):
try:
parsed = pd.to_datetime(df[col])
print(f"[SUCCESS] '{col}' parsed successfully.")
return parsed
except Exception as e:
print(f"[ERROR] Failed to parse '{col}':", e)
# Find non-date-like values to debug
non_datetimes = df[pd.to_datetime(df[col], errors="coerce").isna()][col].unique()
print("Sample values causing issue:", non_datetimes[:5])
raise
df["created_at"] = parse_date_debug(df, "created_at")
df["actual_delivery_time"] = parse_date_debug(df, "actual_delivery_time")
다음은 출력입니다.
이것은 DateTime Parsing이 충돌 할 때 결함이있는 행을 추적하는 데 도움이됩니다.
사례 3 : 오도 할 수있는 순진한 분열
열이 이미 숫자이므로 데이터 프레임에 오류가 발생하지 않습니다. 그러나 여기에는 문제가 있습니다. 일부 데이터 세트는 숫자처럼 보일 때에도 객체 유형으로 몰래 빠져 있습니다. 그것은 다음으로 이어진다.
- 오도 비율
- 잘못된 모델 동작
- 경고가 없습니다
df["busy_dashers_ratio"] = df["total_busy_dashers"] / df["total_onshift_dashers"]
작업에 오류가 발생하지 않더라도 컴퓨팅 전에 유형을 확인하겠습니다.
import numpy as np
def create_ratio_debug(df, num_col, denom_col, new_col):
num_type = df[num_col].dtype
denom_type = df[denom_col].dtype
if not np.issubdtype(num_type, np.number) or not np.issubdtype(denom_type, np.number):
print(f"[TYPE WARNING] '{num_col}' or '{denom_col}' is not numeric.")
print(f"{num_col}: {num_type}, {denom_col}: {denom_type}")
df[new_col] = np.nan
return df
if (df[denom_col] == 0).any():
print(f"[DIVISION WARNING] '{denom_col}' contains zeros.")
df[new_col] = df[num_col] / df[denom_col]
return df
df = create_ratio_debug(df, "total_busy_dashers", "total_onshift_dashers", "busy_dashers_ratio")
다음은 출력입니다.
이는 잠재적 인 부서별로 가시성을 제공하며 침묵의 버그를 방지합니다.
모델링 실수 : 형태 불일치 및 평가 혼동
사례 1 : 기능의 NAN 값이 모델을 충돌시킵니다.
선형 회귀 모델을 구축하고 싶다고 가정 해 봅시다. LinearRegression()
NAN 값을 기본적으로 지원하지 않습니다. X의 행에 결 측값이 있으면 모델은 훈련을 거부합니다.
다음은 의도적으로 오류를 트리거하기 위해 모양 불일치를 생성하는 코드입니다.
from sklearn.linear_model import LinearRegression
X_train = df[["estimated_order_place_duration", "estimated_store_to_consumer_driving_duration"]].iloc[:-10]
y_train = df["actual_total_delivery_duration"].iloc[:-5]
model = LinearRegression()
model.fit(X_train, y_train)
다음은 출력입니다.
이 문제를 디버깅합시다. 먼저, 우리는 NANS를 확인합니다.
print(X_train.isna().sum())
다음은 출력입니다.
좋아, 다른 변수도 확인합시다.
print(y_train.isna().sum())
다음은 출력입니다.
불일치 및 NAN 값은 해결되어야합니다. 다음은이를 해결하는 코드입니다.
from sklearn.linear_model import LinearRegression
# Re-align X and y to have the same length
X = df[["estimated_order_place_duration", "estimated_store_to_consumer_driving_duration"]]
y = df["actual_total_delivery_duration"]
# Step 1: Drop rows with NaN in features (X)
valid_X = X.dropna()
# Step 2: Align y to match the remaining indices of X
y_aligned = y.loc[valid_X.index]
# Step 3: Find indices where y is not NaN
valid_idx = y_aligned.dropna().index
# Step 4: Create final clean datasets
X_clean = valid_X.loc[valid_idx]
y_clean = y_aligned.loc[valid_idx]
model = LinearRegression()
model.fit(X_clean, y_clean)
print("✅ Model trained successfully!")
그리고 Voilà! 다음은 출력입니다.
사례 2 : 객체 열 (날짜)이 모델에 충돌합니다
다음과 같은 타임 스탬프를 사용하여 모델을 훈련 시키려고한다고 가정 해 봅시다. actual_delivery_time
.
그러나 – 아뇨 – 그것은 여전히 객체 또는 datetime 유형이며 실수로 숫자 열과 혼합합니다. 선형 회귀는 그 비트를 좋아하지 않습니다.
from sklearn.linear_model import LinearRegression
X = df[["actual_delivery_time", "estimated_order_place_duration"]]
y = df["actual_total_delivery_duration"]
model = LinearRegression()
model.fit(X, y)
오류 코드는 다음과 같습니다.
X 매트릭스에서 호환되지 않는 두 가지 데이터 유형을 결합하고 있습니다.
- 하나의 열 (
actual_delivery_time
) 이다datetime64
. - 다른 사람 (
estimated_order_place_duration
) 이다int64
.
Scikit-Learn은 모든 기능이 동일한 숫자 DType 일 것으로 기대합니다. DateTime 및 int와 같은 혼합 유형을 처리 할 수 없습니다. DateTime 열을 숫자 표현 (UNIX 타임 스탬프)으로 변환하여 해결해 봅시다.
# Ensure datetime columns are parsed correctly, coercing errors to NaT
df["actual_delivery_time"] = pd.to_datetime(df["actual_delivery_time"], errors="coerce")
df["created_at"] = pd.to_datetime(df["created_at"], errors="coerce")
# Recalculate duration in case of new NaNs
df["actual_total_delivery_duration"] = (df["actual_delivery_time"] - df["created_at"]).dt.total_seconds()
# Convert datetime to a numeric feature (Unix timestamp in seconds)
df["delivery_time_timestamp"] = df["actual_delivery_time"].astype("int64") // 10**9
좋은. DTYPES가 숫자가되었으므로 ML 모델을 적용해 봅시다.
from sklearn.linear_model import LinearRegression
# Use the new numeric timestamp feature
X = df[["delivery_time_timestamp", "estimated_order_place_duration"]]
y = df["actual_total_delivery_duration"]
# Drop any remaining NaNs from our feature set and target
X_clean = X.dropna()
y_clean = y.loc[X_clean.index].dropna()
X_clean = X_clean.loc[y_clean.index]
model = LinearRegression()
model.fit(X_clean, y_clean)
print("✅ Model trained successfully!")
다음은 출력입니다.
좋은 일!
최종 생각 : 디버그 더 똑똑하고 어렵지 않습니다
모델 충돌이 항상 복잡한 버그에서 비롯된 것은 아닙니다. 때로는 길 잃은 NAN 또는 데이터 파이프 라인에 몰래 들어오는 전환되지 않은 날짜 열입니다.
비밀 스택 흔적이나 던지기로 씨름하는 대신 try-except
어둠 속의 다트와 같은 블록은 데이터 프레임을 일찍 파헤칩니다. 엿보기 .info()
확인하다 .isna().sum()
그리고 부끄러워하지 마십시오 .dtypes
. 이 간단한 단계는 당신이 치기 전에 숨겨진 지뢰를 공개합니다. fit()
.
간과 된 객체 유형 또는 교활한 결 측값조차 모델을 방해 할 수 있음을 보여주었습니다. 그러나 더 날카로운 눈, 깨끗한 준비 및 의도적 인 기능 추출로 인해 디버깅에서 지능적으로 빌드로 이동합니다.
네이트 로시디 데이터 과학자이자 제품 전략입니다. 그는 또한 겸임 교수 교육 분석이며, 데이터 과학자들이 최고 회사의 실제 인터뷰 질문과의 인터뷰를 준비하는 플랫폼 인 Stratascratch의 창립자입니다. Nate는 커리어 시장의 최신 트렌드에 대해 글을 쓰고, 인터뷰 조언을 제공하고, 데이터 과학 프로젝트를 공유하며, 모든 SQL을 다룹니다.
Post Comment