pipe()를 사용한 메서드 연결
pipe()로 사용자 정의 함수와 기본 Pandas 메서드를 연결해 읽기 쉬운 데이터 변환 pipeline을 작성합니다.
pipe()를 사용한 메서드 연결은(는) CoddyKit의 무료 Pandas & NumPy Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Pandas & NumPy Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Pandas & NumPy Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
중간 변수의 문제점
pipe()를 사용하지 않는 데이터 정리 파이프라인에는 중간 변수가 계속 쌓이는 경우가 많습니다. 예를 들면 df1 = clean(df), df2 = transform(df1), df3 = enrich(df2)와 같습니다. 이러한 변수는 이름 공간을 복잡하게 만들고 디버깅을 어렵게 하며, 개발자가 변수를 잘못 재사용하게 만들 수 있습니다. 그 결과 변환의 순서를 위에서 아래로 읽기 어려운 코드가 됩니다.
import pandas as pd
df = pd.read_csv('orders.csv')
# Without pipe — intermediate variables everywhere
df1 = df.dropna(subset=['revenue'])
df2 = df1[df1['quantity'] > 0]
df3 = df2.assign(revenue_per_unit=df2['revenue'] / df2['quantity'])
print(df3.shape)pipe() 소개
DataFrame.pipe(func)은 func(df)를 호출하고 그 결과를 반환하므로, .dropna().query()와 같은 기본 Pandas 메서드를 연결하는 것처럼 사용자 지정 함수를 연결할 수 있습니다. 가장 큰 장점은 모든 변환 단계가 왼쪽에서 오른쪽으로 명확하고 읽기 쉽게 표현된다는 점입니다. 괄호를 사용해 형식을 지정하면 위에서 아래의 흐름으로도 표현할 수 있어 파이프라인의 논리적 순서를 그대로 보여 줍니다.
def drop_nulls(df):
return df.dropna(subset=['revenue'])
def filter_positive_qty(df):
return df[df['quantity'] > 0]
def add_revenue_per_unit(df):
return df.assign(revenue_per_unit=df['revenue'] / df['quantity'])
# With pipe — clean chain
df_clean = (df
.pipe(drop_nulls)
.pipe(filter_positive_qty)
.pipe(add_revenue_per_unit)
)
print(df_clean.shape)pipe()로 인수 전달하기
함수 이름 뒤에 키워드 인수를 사용해 파이프에 전달되는 함수에 추가 인수를 전달할 수 있습니다. 예를 들면 df.pipe(func, arg1=val1)과 같습니다. 함수 시그니처는 첫 번째 매개변수로 df를 받아야 합니다. 매개변수화된 함수를 사용하면 파이프라인을 구성 가능하게 만들 수 있습니다. 함수 본문을 수정하지 않고 pipe 호출의 인수만 변경해 임계값, 열 이름 또는 동작을 바꿀 수 있습니다.
def filter_by_region(df, regions):
return df[df['region'].isin(regions)]
def cap_revenue(df, upper):
df = df.copy()
df['revenue'] = df['revenue'].clip(upper=upper)
return df
df_result = (df
.pipe(filter_by_region, regions=['North', 'East'])
.pipe(cap_revenue, upper=1000)
)
print(df_result.shape)pipe()와 기본 메서드 함께 사용하기
pipe()의 강력한 점은 동일한 체인 안에서 Pandas의 기본 메서드와 자연스럽게 통합된다는 것입니다. .dropna(), .query(), .rename(), .pipe(custom_func)를 어떤 순서로든 조합할 수 있습니다. 따라서 이 체인은 가능한 경우 기본 제공 메서드를 사용해 간결하면서도, 기본 메서드로 처리하기 어려운 부분에는 사용자 지정 함수를 사용해 유연합니다.
df_result = (
df
.dropna(subset=['revenue', 'order_date'])
.query('quantity > 0')
.rename(columns={'unit_price': 'price'})
.pipe(add_revenue_per_unit)
.reset_index(drop=True)
)
print(df_result.head())pipe() 체인 디버깅
긴 체인은 중간에 print 문을 추가해 중간 상태를 확인할 수 없기 때문에 디버깅이 까다로울 수 있습니다. 한 가지 해결 방법은 형태와 열 정보를 출력한 다음 DataFrame을 변경하지 않고 그대로 반환하는 통과형 디버그 함수를 작성하는 것입니다. 체인의 어느 지점에든 이 함수를 삽입하면 체인을 중단하지 않고 해당 단계의 상태를 확인할 수 있습니다.
def debug(df, label=''):
print(f'[{label}] shape: {df.shape}')
print(f'[{label}] columns: {df.columns.tolist()}')
return df
df_result = (
df
.pipe(drop_nulls)
.pipe(debug, label='after drop_nulls')
.pipe(filter_positive_qty)
.pipe(debug, label='after filter')
)
print('Done')전체 정리 파이프라인 구축
모든 정리 단계를 pipe()를 사용하는 하나의 파이프라인 함수로 결합해 보겠습니다. 체인을 clean_pipeline(df)라는 함수로 감싸면 파이프라인을 하나의 단위로 테스트할 수 있습니다. 원시 DataFrame을 전달하면 정리된 DataFrame을 반환받습니다. 이 패턴은 실제 데이터 엔지니어링에서 사용하는 ETL(추출, 변환, 적재) 패러다임에 부합합니다.
def clean_pipeline(df):
return (
df
.dropna(subset=['order_id', 'revenue'])
.drop_duplicates(subset=['order_id'])
.query('quantity > 0 and revenue >= 0')
.pipe(add_revenue_per_unit)
.reset_index(drop=True)
)
df_clean = clean_pipeline(df)
print('Clean rows:', len(df_clean))pipe()와 apply()의 주요 차이점
pipe(func)는 전체 DataFrame을 func에 전달하고 DataFrame(또는 변환된 객체)을 반환값으로 기대합니다. apply(func, axis=1)은 한 번에 한 행을 전달합니다. 동일한 형태를 유지하거나 의도적으로 형태를 변경하는 전체 DataFrame 변환에는 pipe()를 사용하고, 행 또는 열 수준의 계산에는 apply()를 사용합니다. 두 함수는 경쟁 관계가 아니라 서로 보완하는 관계입니다.
# pipe: receives the whole DataFrame
def scale_revenue(df, factor=1.0):
df = df.copy()
df['revenue'] = df['revenue'] * factor
return df
# apply: receives one row at a time
df['revenue_x2'] = df.apply(lambda row: row['revenue'] * 2, axis=1)
df_scaled = df.pipe(scale_revenue, factor=1.1)
print('pipe scales all rows at once; apply does row-by-row')재사용 가능한 파이프라인 구성 요소
각 파이프라인 단계를 순수 함수로 작성하십시오. 전역 상태를 사용하지 않고 DataFrame을 받아 DataFrame을 반환해야 합니다. 순수 함수는 작은 테스트용 DataFrame을 전달하고 출력 형태와 열 값을 검증하는 방식으로 단위 테스트하기 쉽습니다. 테스트를 마친 재사용 가능한 파이프라인 함수 모음이 있으면 비슷한 정리 요구 사항을 공유하는 새로운 데이터셋을 훨씬 빠르게 분석할 수 있습니다.
def normalise_strings(df, cols):
df = df.copy()
for col in cols:
df[col] = df[col].str.strip().str.lower()
return df
def parse_dates(df, cols):
df = df.copy()
for col in cols:
df[col] = pd.to_datetime(df[col])
return df
df_result = (
df
.pipe(normalise_strings, cols=['region', 'category'])
.pipe(parse_dates, cols=['order_date'])
)
print(df_result.dtypes)pipe()로 파이프라인 단계 기록하기
각 파이프라인 함수 내부에 구조화된 로깅을 추가하면 실제 운영 환경에서 모든 변환을 감사할 수 있습니다. 입력 행 수, 출력 행 수, 그리고 필터로 삭제된 행 수와 같은 관련 통계를 포함하십시오. 이렇게 하면 기본적인 감사 기록을 위해 외부 작업 흐름 오케스트레이터를 사용하지 않아도 모든 파이프라인 실행을 완전히 추적할 수 있습니다.
import logging
logging.basicConfig(level=logging.INFO)
def logged_dropna(df, subset):
before = len(df)
df = df.dropna(subset=subset)
after = len(df)
logging.info(f'dropna: {before - after} rows removed, {after} remaining')
return df
df_clean = df.pipe(logged_dropna, subset=['revenue'])
print('Logged pipeline complete.')파이프라인의 조건부 단계
때로는 플래그나 데이터 내용에 따라 정리 단계를 실행해야 합니다. 조건을 확인한 뒤 변환을 적용하거나 DataFrame을 변경하지 않고 그대로 반환하는 항등 또는 변환 함수를 체인에 삽입하면 pipe 체인에 조건부 단계를 추가할 수 있습니다. 이렇게 하면 선택적 단계를 지원하면서도 체인의 구조를 유지할 수 있습니다.
def maybe_cap_revenue(df, cap=None):
if cap is None:
return df
df = df.copy()
df['revenue'] = df['revenue'].clip(upper=cap)
return df
CAPPING_ENABLED = True
CAP_VALUE = 1000 if CAPPING_ENABLED else None
df_result = df.pipe(maybe_cap_revenue, cap=CAP_VALUE)
print('Conditional step applied:', CAPPING_ENABLED)파이프라인 결과 내보내기
pipe() 체인의 마지막 단계는 내보내기인 경우가 많습니다. pipe()를 사용해 사용자 지정 내보내기 함수를 연결하거나, 체인 다음에 Pandas의 기본 내보내기 메서드를 바로 호출할 수 있습니다. pipe(save_to_parquet) 단계를 사용하면 내보내기가 체인 문서의 일부로 유지되고, 중간 버전이 아닌 최종적으로 정리된 DataFrame에 대해 항상 실행됩니다.
def save_parquet(df, path):
df.to_parquet(path, index=False)
print(f'Saved {len(df)} rows to {path}')
return df # return df so the chain can continue if needed
df_final = (
df
.pipe(clean_pipeline)
.pipe(save_parquet, path='orders_final.parquet')
)
print('Pipeline complete.')빠른 확인
이 단원에서 배운 데이터 분석 개념에 대한 이해도를 확인해 보십시오.
단원 요약
이 단원에서는 pipe()를 사용해 사용자 지정 함수와 Pandas의 기본 메서드를 연결하는 방법, 순수 함수로 재사용 가능하고 매개변수화할 수 있으며 테스트 가능한 파이프라인 단계를 구축하는 방법, pipe 체인 내부에 디버그 로깅과 조건부 단계를 추가하는 방법을 배웠습니다. 다음 단원에서는 실제 운영 환경의 ETL 파이프라인을 위해 변환 단계를 함수로 구성하는 방법을 살펴봅니다.
자주 묻는 질문
“pipe()를 사용한 메서드 연결” 강의는 무료인가요?
네 — “pipe()를 사용한 메서드 연결” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Pandas & NumPy Academy 강의 전체를 잠금 해제할 수 있습니다. Pandas & NumPy Academy 강의에는 총 4개의 강의가 포함되어 있습니다.
“pipe()를 사용한 메서드 연결”에서 뭘 배우나요?
pipe()로 사용자 정의 함수와 기본 Pandas 메서드를 연결해 읽기 쉬운 데이터 변환 pipeline을 작성합니다. 브라우저에서 직접 실행하는 실습 코드로 Pandas & NumPy Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.
Pandas & NumPy Academy을(를) 시작하는 데 경험이 필요한가요?
사전 경험은 필요하지 않습니다. CoddyKit의 Pandas & NumPy Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.
“pipe()를 사용한 메서드 연결” 강의는 얼마나 걸리나요?
대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.
이 Pandas & NumPy Academy 강의에서 코드를 작성하고 실행할 수 있나요?
네. 모든 Pandas & NumPy Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.
이 강의의 모든 강의
- 열과 행에 apply() 적용하기
- GroupBy와 함께 apply() 사용하기
- 요소별 연산에 map()과 applymap() 사용하기
- pipe()를 사용한 메서드 연결