본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 11. 29. · 14 Views
파생 변수 생성 기법 완벽 가이드
데이터 분석에서 기존 변수들을 조합하여 새로운 의미 있는 변수를 만드는 파생 변수 생성 기법을 다룹니다. 피처 엔지니어링의 핵심인 파생 변수를 통해 모델 성능을 극적으로 향상시키는 방법을 배웁니다.
목차
1. 산술 연산 파생 변수
어느 날 김개발 씨는 쇼핑몰 데이터를 분석하다가 고민에 빠졌습니다. 고객의 구매 금액과 구매 횟수 데이터는 있는데, 정작 알고 싶은 것은 "고객 한 명이 평균적으로 얼마를 쓰는가"였습니다.
기존 데이터만으로는 이 질문에 답할 수 없었습니다.
산술 연산 파생 변수는 기존 변수들을 더하기, 빼기, 곱하기, 나누기 등의 연산으로 조합하여 새로운 변수를 만드는 가장 기본적인 기법입니다. 마치 요리사가 기본 재료들을 조합해 새로운 요리를 만들어내는 것과 같습니다.
이 기법을 활용하면 원본 데이터에는 없던 새로운 인사이트를 발견할 수 있습니다.
다음 코드를 살펴봅시다.
import pandas as pd
# 고객 구매 데이터
df = pd.DataFrame({
'customer_id': [1, 2, 3, 4, 5],
'total_purchase': [150000, 280000, 95000, 420000, 180000],
'purchase_count': [3, 7, 2, 10, 4]
})
# 파생 변수 생성: 평균 구매 금액
df['avg_purchase'] = df['total_purchase'] / df['purchase_count']
# 파생 변수 생성: 구매력 점수 (총액 * 횟수의 제곱근)
df['purchase_power'] = df['total_purchase'] * (df['purchase_count'] ** 0.5)
print(df)
김개발 씨는 입사 6개월 차 데이터 분석가입니다. 오늘 팀장님으로부터 "VIP 고객을 선별하는 기준을 만들어 보라"는 과제를 받았습니다.
막막했습니다. 데이터에는 총 구매 금액과 구매 횟수만 있을 뿐, VIP를 판단할 명확한 기준이 없었기 때문입니다.
옆자리의 박시니어 씨가 김개발 씨의 화면을 슬쩍 보더니 말했습니다. "원본 데이터만 쳐다보지 말고, 데이터를 조합해서 새로운 변수를 만들어 보는 건 어때요?" 그렇다면 산술 연산 파생 변수란 정확히 무엇일까요?
쉽게 비유하자면, 산술 연산 파생 변수는 마치 레고 블록을 조합하는 것과 같습니다. 빨간 블록과 파란 블록을 각각 보면 그냥 블록일 뿐이지만, 둘을 조합하면 자동차가 되기도 하고 집이 되기도 합니다.
마찬가지로 총 구매 금액과 구매 횟수라는 두 변수를 나누면 평균 구매 금액이라는 완전히 새로운 의미의 변수가 탄생합니다. 파생 변수가 없던 시절에는 어땠을까요?
분석가들은 원본 데이터의 컬럼만 가지고 분석을 시도했습니다. 하지만 원본 데이터는 대부분 시스템이 기록한 로그 형태입니다.
비즈니스 관점에서 의미 있는 지표와는 거리가 멀었습니다. 예를 들어 "이 고객이 충성 고객인가?"라는 질문에 단순히 구매 횟수 하나만으로는 답하기 어렵습니다.
바로 이런 한계를 극복하기 위해 파생 변수 생성 기법이 발전했습니다. 파생 변수를 만들면 첫째, 비즈니스 질문에 직접 답할 수 있는 지표를 얻습니다.
둘째, 머신러닝 모델의 성능을 크게 향상시킬 수 있습니다. 셋째, 데이터에 숨겨진 패턴을 발견하는 열쇠가 됩니다.
위의 코드를 한 줄씩 살펴보겠습니다. 먼저 avg_purchase 변수를 만드는 부분을 보면, 총 구매 금액을 구매 횟수로 나누고 있습니다.
이것이 바로 "1회 평균 얼마를 쓰는가"라는 질문에 대한 답입니다. 다음으로 purchase_power 변수는 총 구매 금액에 구매 횟수의 제곱근을 곱합니다.
횟수가 많을수록 가산점을 주되, 그 효과를 완만하게 만든 것입니다. 실제 현업에서는 어떻게 활용할까요?
금융권에서는 월 수입과 월 지출로 저축률을 계산합니다. 이커머스에서는 장바구니 금액과 실제 결제 금액으로 쿠폰 사용률을 도출합니다.
게임 회사에서는 접속 시간과 접속 일수로 일평균 플레이 시간을 만듭니다. 하지만 주의할 점도 있습니다.
나누기 연산을 할 때 분모가 0이 되는 경우를 반드시 처리해야 합니다. 또한 단위가 다른 변수들을 무작정 곱하면 해석이 어려운 괴상한 숫자가 나올 수 있습니다.
파생 변수는 반드시 비즈니스 의미가 있어야 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
평균 구매 금액과 구매력 점수라는 파생 변수를 만든 김개발 씨는 드디어 VIP 선별 기준의 실마리를 찾았습니다. "아, 이렇게 조합하면 되는군요!" 산술 연산 파생 변수는 가장 기본이지만 가장 강력한 무기입니다.
여러분도 가지고 있는 데이터를 다양하게 조합해 보세요.
실전 팁
💡 - 나누기 연산 시 df['col'].replace(0, np.nan)으로 0 처리 먼저 하기
- 파생 변수명은 비즈니스 의미가 드러나도록 명확하게 짓기
- 새로 만든 변수의 분포를 반드시 시각화로 확인하기
2. 날짜 시간 파생 변수
김개발 씨는 이번에는 주문 데이터를 분석하고 있었습니다. 주문 일시 데이터는 있는데, "주말에 주문이 더 많은가?"라는 질문에는 답할 수 없었습니다.
날짜 데이터를 어떻게 활용해야 할지 막막했습니다.
날짜 시간 파생 변수는 타임스탬프나 날짜 데이터에서 연도, 월, 요일, 시간대 등을 추출하여 새로운 변수를 만드는 기법입니다. 마치 생년월일에서 나이, 띠, 별자리를 알아내는 것과 같습니다.
시계열 데이터 분석과 계절성 패턴 발견에 필수적인 기법입니다.
다음 코드를 살펴봅시다.
import pandas as pd
# 주문 데이터
df = pd.DataFrame({
'order_id': [1, 2, 3, 4, 5],
'order_datetime': pd.to_datetime([
'2024-01-15 09:30:00', '2024-01-15 14:20:00',
'2024-01-20 22:15:00', '2024-01-21 11:00:00',
'2024-02-03 16:45:00'
])
})
# 날짜/시간 파생 변수 생성
df['year'] = df['order_datetime'].dt.year
df['month'] = df['order_datetime'].dt.month
df['day_of_week'] = df['order_datetime'].dt.dayofweek # 0=월요일
df['hour'] = df['order_datetime'].dt.hour
df['is_weekend'] = df['day_of_week'].isin([5, 6]).astype(int)
print(df)
김개발 씨는 마케팅팀의 요청을 받았습니다. "언제 프로모션을 하면 효과가 좋을까요?" 단순해 보이는 질문이지만, 주문 데이터의 order_datetime 컬럼만 봐서는 아무것도 알 수 없었습니다.
2024-01-15 09:30:00이라는 숫자의 나열이 뭘 의미하는지 컴퓨터도 모르고, 분석도 할 수 없었습니다. 박시니어 씨가 조언했습니다.
"날짜 데이터는 금광 같아요. 그 안에서 보석을 캐내야 합니다." 그렇다면 날짜 시간 파생 변수란 무엇일까요?
쉽게 비유하자면, 주민등록번호에서 생년월일, 성별, 출생 지역 정보를 추출하는 것과 같습니다. 하나의 긴 숫자에 여러 정보가 압축되어 있는 것처럼, 날짜 데이터 하나에도 연도, 월, 일, 요일, 시간, 분기 등 수많은 정보가 담겨 있습니다.
날짜를 그냥 문자열로만 다루면 어떤 문제가 생길까요? 머신러닝 모델은 "2024-01-15"라는 문자열을 이해하지 못합니다.
또한 "1월 15일이 무슨 요일인가?", "이건 겨울인가 여름인가?"와 같은 맥락적 정보를 활용할 수 없습니다. 결국 시간의 흐름이나 주기성을 전혀 파악하지 못하게 됩니다.
바로 이런 문제를 해결하기 위해 날짜 시간 파생 변수를 생성합니다. dt 접근자를 사용하면 Pandas에서 손쉽게 날짜 구성 요소를 추출할 수 있습니다.
year, month, day, hour, minute, second는 물론이고, dayofweek, quarter, is_month_start 같은 유용한 속성도 제공됩니다. 위의 코드에서 특히 주목할 부분은 is_weekend 변수입니다.
dayofweek가 5(토요일) 또는 6(일요일)인지를 판단하여 0과 1로 변환했습니다. 이렇게 만든 이진 변수는 "주말 효과"를 분석하는 데 바로 사용할 수 있습니다.
복잡한 요일 숫자보다 훨씬 직관적입니다. 실제 현업에서는 다양한 날짜 파생 변수가 활용됩니다.
배달 앱에서는 점심 시간대(11시~13시) 여부를 변수로 만들어 주문 패턴을 분석합니다. 리테일에서는 월초/월말 변수로 급여일 효과를 파악합니다.
여행 업계에서는 휴가 시즌 변수로 성수기를 정의합니다. 주의할 점도 있습니다.
타임존 처리를 잘못하면 엉뚱한 결과가 나올 수 있습니다. 서버 시간과 사용자 현지 시간이 다를 수 있기 때문입니다.
또한 공휴일은 dayofweek만으로는 알 수 없으므로 별도의 공휴일 데이터를 조인해야 합니다. 김개발 씨는 주말 변수와 시간대 변수를 만들어 분석한 결과, 토요일 오후 2시에 주문이 가장 많다는 것을 발견했습니다.
마케팅팀은 이 인사이트로 프로모션 시간을 최적화할 수 있었습니다. 날짜 데이터는 반드시 분해해서 사용하세요.
그 안에 비즈니스 인사이트가 숨어 있습니다.
실전 팁
💡 - pd.to_datetime()으로 먼저 datetime 타입으로 변환하기
- 한국 공휴일은 holidays 라이브러리 활용하기
- 시간대는 비즈니스 맥락에 맞게 구간화하기 (새벽/아침/점심/저녁/밤)
3. 구간화 범주형 변환
김개발 씨는 나이 데이터를 분석하고 있었습니다. 25세, 27세, 29세 고객의 행동이 크게 다를까요?
아마 비슷할 것입니다. 그렇다면 어떻게 해야 이들을 의미 있는 그룹으로 묶을 수 있을까요?
구간화는 연속형 변수를 특정 기준으로 나누어 범주형 변수로 변환하는 기법입니다. 마치 학교에서 점수를 A, B, C, D, F 등급으로 나누는 것과 같습니다.
노이즈를 줄이고 의미 있는 그룹을 만들어 분석의 해석력을 높여줍니다.
다음 코드를 살펴봅시다.
import pandas as pd
df = pd.DataFrame({
'customer_id': [1, 2, 3, 4, 5, 6],
'age': [23, 35, 28, 52, 41, 19],
'income': [2800, 5200, 3500, 8100, 6300, 2100]
})
# 나이 구간화 (pd.cut 사용)
df['age_group'] = pd.cut(df['age'],
bins=[0, 20, 30, 40, 50, 100],
labels=['10대', '20대', '30대', '40대', '50대+'])
# 소득 분위수 기반 구간화 (pd.qcut 사용)
df['income_level'] = pd.qcut(df['income'],
q=3,
labels=['저소득', '중소득', '고소득'])
print(df)
김개발 씨는 고객 세분화 프로젝트를 맡았습니다. 나이와 소득 데이터로 고객을 그룹화해야 하는데, 나이 23세와 24세 고객을 다른 그룹으로 분류하는 것이 과연 의미가 있을까요?
박시니어 씨가 말했습니다. "연속형 데이터는 때로는 덜 정밀하게 보는 것이 더 나은 통찰을 줍니다." 구간화란 정확히 무엇일까요?
비유하자면, 온도계의 숫자를 보지 않고 "춥다, 시원하다, 따뜻하다, 덥다"로 느끼는 것과 같습니다. 24.7도와 25.1도의 차이보다 "따뜻하다"라는 범주가 우리의 행동을 더 잘 설명합니다.
마찬가지로 나이 27세와 28세의 차이보다 "20대"라는 범주가 소비 패턴을 더 잘 설명할 수 있습니다. 구간화를 하지 않으면 어떤 문제가 생길까요?
첫째, 과적합 위험이 있습니다. 모델이 27세와 28세의 미세한 차이까지 학습하려고 하면 일반화 능력이 떨어집니다.
둘째, 이상치에 민감해집니다. 나이 150세라는 잘못된 데이터가 전체 분석을 망칠 수 있습니다.
셋째, 해석이 어렵습니다. "나이가 1살 증가할 때마다 구매 확률이 0.3% 증가한다"보다 "40대가 20대보다 구매율이 높다"가 더 이해하기 쉽습니다.
Pandas에서는 두 가지 구간화 함수를 제공합니다. pd.cut은 우리가 직접 구간 경계를 지정합니다.
나이를 10대, 20대, 30대로 나누는 것처럼 비즈니스 논리에 맞는 구간을 만들 때 사용합니다. 반면 pd.qcut은 데이터를 동일한 개수로 나눕니다.
상위 33%, 중위 33%, 하위 33%처럼 분위수 기반으로 나눌 때 유용합니다. 위의 코드에서 income_level을 만들 때 qcut을 사용한 이유가 있습니다.
소득은 나라마다, 시대마다 기준이 다릅니다. 절대적인 금액으로 "고소득"을 정의하기 어렵습니다.
하지만 "상위 33%"라는 상대적 기준은 어느 데이터셋에서나 적용 가능합니다. 실제 현업에서는 구간화가 광범위하게 사용됩니다.
신용평가에서는 신용 점수를 1~10등급으로 나눕니다. 마케팅에서는 RFM 점수를 고객 등급으로 변환합니다.
의료 분야에서는 BMI를 저체중, 정상, 과체중, 비만으로 분류합니다. 하지만 주의할 점이 있습니다.
구간의 경계를 어디에 두느냐에 따라 분석 결과가 크게 달라질 수 있습니다. 30세를 20대에 넣을지 30대에 넣을지에 따라 인사이트가 바뀔 수 있습니다.
따라서 도메인 지식을 바탕으로 의미 있는 경계를 설정해야 합니다. 김개발 씨는 나이를 연령대로, 소득을 분위수로 구간화하여 깔끔한 고객 세그먼트를 만들었습니다.
마케팅팀은 "30대 고소득층"이라는 명확한 타겟을 정의할 수 있게 되었습니다.
실전 팁
💡 - cut의 bins에 -np.inf, np.inf를 사용하면 극단값도 포함됨
- qcut에서 중복값이 많으면 duplicates='drop' 옵션 사용하기
- 구간 경계는 반드시 비즈니스 담당자와 협의하기
4. 집계 기반 파생 변수
김개발 씨는 고객별 분석을 하고 있었습니다. 그런데 데이터는 주문 단위로 되어 있습니다.
한 고객이 여러 번 주문한 기록이 각각의 행으로 존재합니다. 어떻게 해야 "이 고객의 평균 주문 금액"을 알 수 있을까요?
집계 기반 파생 변수는 groupby 연산을 통해 특정 기준으로 데이터를 그룹화하고, 합계, 평균, 최대, 최소, 개수 등을 계산하여 새로운 변수를 만드는 기법입니다. 마치 반별로 학생들의 평균 점수를 구하는 것과 같습니다.
트랜잭션 데이터를 엔티티 수준으로 요약할 때 필수적입니다.
다음 코드를 살펴봅시다.
import pandas as pd
# 주문 데이터 (트랜잭션 레벨)
orders = pd.DataFrame({
'customer_id': [1, 1, 1, 2, 2, 3],
'order_amount': [50000, 75000, 30000, 120000, 80000, 45000],
'order_date': pd.to_datetime(['2024-01-10', '2024-01-15', '2024-02-01',
'2024-01-20', '2024-02-10', '2024-01-25'])
})
# 고객별 집계 파생 변수 생성
customer_stats = orders.groupby('customer_id').agg(
total_orders=('order_amount', 'count'),
total_spent=('order_amount', 'sum'),
avg_order=('order_amount', 'mean'),
max_order=('order_amount', 'max'),
last_order_date=('order_date', 'max')
).reset_index()
print(customer_stats)
김개발 씨는 추천 시스템을 만들기 위해 고객 프로파일을 구축하고 있었습니다. 그런데 데이터베이스에서 가져온 데이터는 주문 테이블이었습니다.
고객 1번이 세 번 주문하면 세 개의 행이 있습니다. 이 상태로는 "고객 1번은 어떤 사람인가?"라는 질문에 답할 수 없었습니다.
박시니어 씨가 다가와 물었습니다. "그 주문 데이터를 고객 단위로 요약해 봤어요?" 집계 기반 파생 변수란 무엇일까요?
비유하자면, 학교에서 학생 개개인의 시험 점수 기록이 있을 때, 반별 평균 점수를 구하는 것과 같습니다. 개별 기록들을 특정 기준으로 묶어서 요약 통계를 내는 것입니다.
이렇게 하면 "1반이 2반보다 성적이 좋다"와 같은 비교가 가능해집니다. 왜 집계가 필요할까요?
머신러닝 모델은 보통 하나의 행이 하나의 예측 대상을 나타내야 합니다. 고객 이탈을 예측하려면 고객당 한 행이 있어야 합니다.
하지만 원본 데이터는 대부분 트랜잭션 수준입니다. 주문, 클릭, 로그인 등 행위 하나하나가 각각의 행입니다.
이 간극을 메우는 것이 바로 집계입니다. 위의 코드에서 agg 함수의 사용법을 살펴보겠습니다.
딕셔너리 형태로 새 컬럼명과 (원본 컬럼, 집계 함수) 튜플을 지정합니다. 이 방식을 named aggregation이라고 합니다.
가독성이 좋고, 한 번에 여러 집계를 수행할 수 있어서 실무에서 매우 유용합니다. 다양한 집계 함수를 활용할 수 있습니다.
count는 개수, sum은 합계, mean은 평균, max와 min은 최대최소, std는 표준편차, first와 last는 처음과 마지막 값을 반환합니다. nunique는 고유값의 개수를 세어줍니다.
이 함수들을 조합하면 엔티티의 다양한 특성을 수치화할 수 있습니다. 실제 현업에서는 어떤 집계 변수를 만들까요?
금융에서는 고객의 월평균 거래 건수, 최대 거래 금액, 거래 빈도 표준편차를 만듭니다. 이커머스에서는 최근 구매일로부터 경과 일수(Recency), 구매 빈도(Frequency), 총 구매 금액(Monetary)을 계산합니다.
이것이 유명한 RFM 분석의 기초입니다. 주의할 점도 있습니다.
집계 후 원본 데이터와 다시 조인해야 할 때가 있습니다. 이때 merge 또는 transform을 적절히 사용해야 합니다.
또한 그룹 내 데이터가 하나뿐인 경우, 표준편차 등의 통계량이 NaN이 될 수 있으므로 후처리가 필요합니다. 김개발 씨는 주문 데이터를 고객별로 집계하여 총 주문 횟수, 평균 주문 금액, 마지막 주문일 등의 변수를 만들었습니다.
이제 각 고객을 한 줄로 설명할 수 있게 되었습니다. 집계 파생 변수는 트랜잭션 데이터를 분석 가능한 형태로 바꾸는 마법의 열쇠입니다.
실전 팁
💡 - transform을 사용하면 집계 결과를 원본 행에 브로드캐스팅할 수 있음
- 집계 전에 이상치를 먼저 처리하면 결과가 더 안정적임
- 다양한 시간 윈도우(최근 7일, 30일, 90일)로 집계하면 트렌드 파악 가능
5. 비율 및 변화율 파생 변수
김개발 씨는 월별 매출 데이터를 보고 있었습니다. 1월 매출 1억, 2월 매출 1억 2천만 원.
숫자만 보면 2월이 더 좋아 보입니다. 하지만 "얼마나 성장했는가?"라는 질문에는 절대 금액으로 답하기 어렵습니다.
성장률이 필요합니다.
비율 및 변화율 파생 변수는 두 값의 비율이나 시간에 따른 변화량을 계산하여 새로운 변수를 만드는 기법입니다. 마치 "작년 대비 올해 성적이 얼마나 올랐는가"를 백분율로 표현하는 것과 같습니다.
성장, 감소, 변동의 정도를 수치화하여 트렌드를 파악할 수 있게 해줍니다.
다음 코드를 살펴봅시다.
import pandas as pd
df = pd.DataFrame({
'month': ['2024-01', '2024-02', '2024-03', '2024-04'],
'revenue': [100000000, 120000000, 110000000, 140000000],
'cost': [60000000, 70000000, 65000000, 80000000],
'visitors': [50000, 60000, 55000, 70000]
})
# 수익률 (비율 변수)
df['profit_margin'] = (df['revenue'] - df['cost']) / df['revenue'] * 100
# 전월 대비 성장률 (변화율 변수)
df['revenue_growth'] = df['revenue'].pct_change() * 100
# 방문자당 매출 (효율성 비율)
df['revenue_per_visitor'] = df['revenue'] / df['visitors']
print(df)
김개발 씨는 경영진 보고용 대시보드를 만들고 있었습니다. 월별 매출 숫자를 그대로 보여주니 대표님이 물었습니다.
"그래서 성장하고 있는 건가요, 아닌 건가요?" 절대 수치만으로는 이 질문에 명확히 답하기 어려웠습니다. 박시니어 씨가 조언했습니다.
"숫자 자체보다 숫자의 변화에 주목하세요. 그게 비즈니스입니다." 비율과 변화율은 왜 중요할까요?
비유하자면, 키 180cm인 사람과 키 150cm인 사람이 각각 10kg 감량했다고 합시다. 같은 10kg이지만 체중 대비 감량 비율은 다릅니다.
절대 수치보다 비율이 더 의미 있는 비교를 가능하게 합니다. 절대 수치만 사용하면 어떤 문제가 생길까요?
규모가 다른 것들을 비교할 수 없습니다. 대기업의 매출 10억 증가와 스타트업의 매출 1억 증가 중 어느 쪽이 더 인상적일까요?
성장률로 비교해야 합니다. 또한 트렌드를 파악하기 어렵습니다.
매출이 1억에서 1.5억이 되었는지, 10억에서 10.5억이 되었는지에 따라 의미가 완전히 다릅니다. 위의 코드에서 세 가지 유형의 비율 변수를 만들었습니다.
첫째, profit_margin은 수익률입니다. (매출 - 비용) / 매출로 계산합니다.
둘째, revenue_growth는 전월 대비 성장률입니다. pct_change() 함수가 자동으로 (현재값 - 이전값) / 이전값을 계산해 줍니다.
셋째, revenue_per_visitor는 효율성 지표입니다. 방문자 한 명당 얼마의 매출을 올리는지를 보여줍니다.
pct_change 함수를 자세히 살펴보겠습니다. 이 함수는 시계열 데이터에서 변화율을 계산하는 데 최적화되어 있습니다.
periods 파라미터로 몇 기간 전과 비교할지 지정할 수 있습니다. periods=3이면 3개월 전 대비 성장률이 됩니다.
첫 번째 행은 이전 값이 없으므로 NaN이 됩니다. 실제 현업에서는 어떤 비율 변수를 만들까요?
금융에서는 전년 동기 대비 성장률(YoY)과 전분기 대비 성장률(QoQ)이 필수입니다. 마케팅에서는 전환율(구매자/방문자), 이탈률(이탈자/전체)을 계산합니다.
SaaS에서는 LTV/CAC 비율로 고객 획득의 효율성을 측정합니다. 주의할 점도 있습니다.
분모가 0이거나 매우 작으면 비율이 무한대가 되거나 극단적으로 커집니다. 매출 100원에서 1000원이 되면 성장률 900%입니다.
이런 극단값을 어떻게 처리할지 미리 정해야 합니다. 또한 음수에서 양수로 전환되는 경우(적자에서 흑자 전환) 성장률 해석에 주의가 필요합니다.
김개발 씨는 성장률과 수익률 변수를 추가한 대시보드를 만들었습니다. 대표님은 한눈에 "2월에 20% 성장했고, 수익률은 40% 수준을 유지하고 있군요"라고 파악할 수 있게 되었습니다.
비율과 변화율은 비즈니스 의사결정의 언어입니다. 절대 수치를 비율로 바꾸는 습관을 들이세요.
실전 팁
💡 - pct_change의 첫 행은 NaN이므로 fillna(0) 또는 dropna() 처리 필요
- 극단적인 비율값은 clip() 함수로 상한/하한 제한하기
- YoY, MoM, WoW 등 다양한 시간 단위의 변화율을 함께 보기
6. 텍스트 기반 파생 변수
김개발 씨는 상품 리뷰 데이터를 분석하고 있었습니다. "이 제품 정말 좋아요!
강력 추천합니다!!!" 같은 텍스트가 수만 개 있었습니다. 이 텍스트에서 어떻게 의미 있는 숫자 변수를 뽑아낼 수 있을까요?
텍스트 기반 파생 변수는 문자열 데이터에서 길이, 단어 수, 특정 패턴 포함 여부 등을 추출하여 수치형 변수로 변환하는 기법입니다. 마치 편지를 읽지 않고도 편지의 길이, 감탄사 개수로 보낸 사람의 감정을 추측하는 것과 같습니다.
자연어 처리의 기초이자 간단하면서도 강력한 피처 엔지니어링 기법입니다.
다음 코드를 살펴봅시다.
import pandas as pd
df = pd.DataFrame({
'review_id': [1, 2, 3, 4],
'review_text': [
'정말 좋아요! 강력 추천합니다!!!',
'그저 그래요. 기대했던 것보다는...',
'최악입니다. 환불 원해요.',
'배송 빠르고 상품도 괜찮네요 ㅎㅎ'
]
})
# 텍스트 길이
df['text_length'] = df['review_text'].str.len()
# 단어 수
df['word_count'] = df['review_text'].str.split().str.len()
# 느낌표 개수 (감정 강도의 힌트)
df['exclamation_count'] = df['review_text'].str.count('!')
# 특정 키워드 포함 여부
df['has_recommend'] = df['review_text'].str.contains('추천').astype(int)
print(df)
김개발 씨는 고객 만족도를 예측하는 모델을 만들어야 했습니다. 그런데 가장 중요한 정보인 리뷰 텍스트는 숫자가 아니었습니다.
"이걸 어떻게 모델에 넣죠?" 박시니어 씨가 힌트를 주었습니다. "텍스트 자체를 넣을 수 없다면, 텍스트의 특성을 숫자로 바꿔보세요." 텍스트 기반 파생 변수란 무엇일까요?
비유하자면, 책을 읽지 않고도 책의 두께, 그림 개수, 대화문 비율만으로 어린이 책인지 학술서인지 짐작하는 것과 같습니다. 텍스트의 내용이 아닌 형식적 특성에서 정보를 추출하는 것입니다.
왜 이런 단순한 특성이 유용할까요? 리뷰 텍스트가 길다는 것은 고객이 할 말이 많다는 뜻입니다.
극찬이든 극혐이든 강한 감정을 가진 경우가 많습니다. 느낌표가 많다는 것은 감정 강도가 높다는 신호입니다.
"추천"이라는 단어가 있다면 긍정적인 리뷰일 가능성이 높습니다. 위의 코드에서 str 접근자의 다양한 메서드를 사용했습니다.
len()은 문자열 길이, split()은 공백 기준 분리, count()는 특정 문자 개수, contains()는 패턴 포함 여부를 반환합니다. 이 메서드들을 조합하면 텍스트에서 다양한 수치를 뽑아낼 수 있습니다.
실제 현업에서는 어떤 텍스트 변수를 만들까요? 고객센터에서는 문의 텍스트의 길이로 문제의 복잡도를 추정합니다.
스팸 필터에서는 대문자 비율, 링크 개수, 특수문자 빈도를 피처로 사용합니다. 소셜 미디어 분석에서는 해시태그 개수, 멘션 수, 이모티콘 빈도를 추출합니다.
더 고급 기법도 있습니다. 정규표현식을 활용하면 이메일 주소 개수, 전화번호 포함 여부, 욕설 패턴 등 복잡한 패턴도 추출할 수 있습니다.
또한 한글의 경우 자음, 모음 비율이나 초성 추출 같은 한국어 특화 피처도 가능합니다. 주의할 점도 있습니다.
텍스트 전처리가 중요합니다. 공백이 여러 개 있으면 word_count가 부정확해집니다.
또한 이모티콘, 특수문자의 처리 방식을 일관되게 정해야 합니다. 인코딩 문제로 이상한 문자가 섞여 있으면 길이 계산도 틀어집니다.
김개발 씨는 리뷰 텍스트에서 5개의 변수를 추출했습니다. 느낌표가 3개 이상이고 "추천" 키워드가 있으면 대부분 별점 5점이라는 패턴을 발견했습니다.
텍스트 파생 변수는 복잡한 NLP 기법을 쓰기 전에 시도해 볼 가치가 있는 간단하면서도 효과적인 방법입니다.
실전 팁
💡 - str.strip()으로 앞뒤 공백 제거 후 분석하기
- 정규표현식은 str.extract()와 str.findall()로 활용
- 영어와 한글이 섞인 경우 각각의 비율도 유용한 피처가 됨
7. 플래그 및 이진 변수
김개발 씨는 이상 거래를 탐지하는 모델을 만들고 있었습니다. "거래 금액이 평소보다 5배 이상 크면 의심 거래로 본다"라는 규칙이 있었습니다.
이 규칙을 어떻게 데이터로 표현할 수 있을까요?
플래그 및 이진 변수는 특정 조건을 만족하는지 여부를 0과 1로 표현하는 파생 변수입니다. 마치 체크리스트에서 "예/아니오"로 답하는 것과 같습니다.
복잡한 비즈니스 규칙을 단순한 이진 신호로 변환하여 모델이 쉽게 학습할 수 있게 해줍니다.
다음 코드를 살펴봅시다.
import pandas as pd
import numpy as np
df = pd.DataFrame({
'transaction_id': [1, 2, 3, 4, 5],
'amount': [50000, 5000000, 30000, 150000, 80000],
'avg_amount': [40000, 100000, 35000, 50000, 75000],
'hour': [14, 3, 10, 22, 16],
'country': ['KR', 'US', 'KR', 'CN', 'KR']
})
# 평균의 5배 이상인 경우 플래그
df['is_high_amount'] = (df['amount'] > df['avg_amount'] * 5).astype(int)
# 새벽 시간대(0-6시) 거래 플래그
df['is_night_transaction'] = df['hour'].between(0, 6).astype(int)
# 해외 거래 플래그
df['is_foreign'] = (df['country'] != 'KR').astype(int)
# 복합 조건: 새벽 + 해외 + 고액
df['is_suspicious'] = (
(df['is_high_amount'] == 1) |
((df['is_night_transaction'] == 1) & (df['is_foreign'] == 1))
).astype(int)
print(df)
김개발 씨는 금융팀과 미팅을 했습니다. "새벽에 해외에서 들어오는 큰 금액의 거래는 사기일 가능성이 높아요." 도메인 전문가의 이 지식을 어떻게 데이터에 녹여낼 수 있을까요?
박시니어 씨가 말했습니다. "전문가의 규칙을 변수로 만드세요.
그게 피처 엔지니어링의 정수입니다." 플래그 변수란 무엇일까요? 비유하자면, 공항 보안 검색대의 경고등과 같습니다.
위험 요소가 감지되면 빨간불이 켜지고, 아니면 꺼져 있습니다. 복잡한 판단 기준이 있지만, 최종 출력은 "위험/안전" 두 가지뿐입니다.
왜 이진 변수가 강력할까요? 첫째, 해석이 쉽습니다.
is_high_amount가 1이라는 것은 즉시 "고액 거래"라고 이해됩니다. 둘째, 도메인 지식을 주입할 수 있습니다.
전문가의 경험적 규칙을 모델에 직접 알려주는 셈입니다. 셋째, 모델 성능을 높입니다.
모델이 스스로 "5배 이상"이라는 규칙을 찾아내기는 어렵지만, 피처로 제공하면 바로 활용합니다. 위의 코드에서 다양한 조건 표현 방식을 사용했습니다.
비교 연산자(>, ==, !=)로 단순 조건을 만들고, between() 메서드로 범위 조건을 표현했습니다. 여러 조건을 &(and)와 |(or)로 조합하여 복합 조건도 만들었습니다.
astype(int)를 붙이는 이유가 있습니다. 조건식의 결과는 True/False의 불리언 타입입니다.
이를 0과 1의 정수로 변환해야 대부분의 머신러닝 모델에서 사용할 수 있습니다. 또한 sum()이나 mean() 같은 집계 함수를 적용하기도 쉬워집니다.
실제 현업에서는 어떤 플래그 변수를 만들까요? 마케팅에서는 is_churned(이탈 여부), is_first_purchase(첫 구매 여부), has_coupon_used(쿠폰 사용 여부)를 만듭니다.
의료에서는 is_abnormal(정상 범위 이탈), has_history(병력 유무)를 정의합니다. 게임에서는 is_whale(고과금러), is_bot_suspect(봇 의심)를 표시합니다.
주의할 점도 있습니다. 플래그 변수를 너무 많이 만들면 차원의 저주가 발생할 수 있습니다.
또한 조건의 임계값(threshold)을 어떻게 정하느냐에 따라 결과가 크게 달라집니다. "5배 이상"이라는 기준이 4배면 안 되는 이유가 있어야 합니다.
김개발 씨는 세 개의 개별 플래그와 하나의 복합 플래그를 만들었습니다. is_suspicious 변수 하나만으로도 이상 거래 탐지 모델의 정밀도가 크게 향상되었습니다.
플래그 변수는 도메인 전문가의 지식을 데이터로 번역하는 통역사와 같습니다. 비즈니스 규칙이 있다면 변수로 만드세요.
실전 팁
💡 - np.where(조건, 1, 0)으로도 이진 변수 생성 가능
- 복합 조건은 가독성을 위해 개별 플래그를 먼저 만들고 조합하기
- 임계값의 근거를 문서화해 두면 나중에 유지보수가 쉬움
8. 시차 및 이동 변수
김개발 씨는 주식 데이터를 분석하고 있었습니다. 오늘 주가가 어제보다 올랐는지 알고 싶었습니다.
하지만 데이터에는 오늘 주가만 있을 뿐, "어제 주가"라는 컬럼은 없었습니다. 어떻게 어제 데이터를 오늘 행에 가져올 수 있을까요?
시차 및 이동 변수는 시계열 데이터에서 과거 값을 현재 행으로 가져오거나(lag), 일정 구간의 평균을 계산하는(rolling) 기법입니다. 마치 달력을 넘겨가며 "3일 전에 뭐 했더라?"를 확인하는 것과 같습니다.
시계열 예측과 패턴 분석의 핵심 도구입니다.
다음 코드를 살펴봅시다.
import pandas as pd
df = pd.DataFrame({
'date': pd.date_range('2024-01-01', periods=7),
'price': [100, 102, 98, 105, 103, 110, 108],
'volume': [1000, 1200, 800, 1500, 1100, 1800, 1300]
})
# 시차 변수: 1일 전 가격
df['price_lag1'] = df['price'].shift(1)
# 시차 변수: 2일 전 가격
df['price_lag2'] = df['price'].shift(2)
# 전일 대비 변화량
df['price_change'] = df['price'] - df['price_lag1']
# 이동 평균: 최근 3일 평균 가격
df['price_ma3'] = df['price'].rolling(window=3).mean()
# 이동 표준편차: 변동성 측정
df['price_volatility'] = df['price'].rolling(window=3).std()
print(df)
김개발 씨는 주가 예측 모델을 만들려고 했습니다. 문제는 "오늘 주가를 예측하려면 어제 주가를 알아야 하는데, 어제 주가는 다른 행에 있다"는 점이었습니다.
데이터프레임에서 행과 행 사이를 어떻게 연결할 수 있을까요? 박시니어 씨가 설명했습니다.
"shift 함수가 시간 여행을 시켜줍니다." **시차 변수(Lag Variable)**란 무엇일까요? 비유하자면, 오늘 일기를 쓰면서 "어제 날씨는 맑았다"라고 적는 것과 같습니다.
어제의 정보를 오늘 기록에 함께 적어두는 것입니다. shift(1)은 한 행 위의 값을 가져옵니다.
shift(2)는 두 행 위의 값을 가져옵니다. **이동 평균(Rolling Mean)**은 무엇일까요?
비유하자면, 일주일 평균 수면 시간을 계산하는 것과 같습니다. 특정 시점 기준으로 최근 N일간의 평균을 구합니다.
이 값은 매일 갱신되며 "이동"합니다. rolling(window=3).mean()은 자기 자신을 포함한 최근 3개 값의 평균입니다.
왜 이런 변수가 중요할까요? 시계열 예측에서 가장 강력한 예측 변수는 직전 값입니다.
"내일 날씨는 오늘과 비슷할 가능성이 높다"는 것은 상식이기도 합니다. Lag 변수를 만들면 이 상식을 모델에 주입할 수 있습니다.
이동 평균은 추세를 보여줍니다. 일시적인 등락을 평균화하여 전반적인 방향성을 파악합니다.
이동 표준편차는 변동성을 측정합니다. 값이 크면 불안정하고, 작으면 안정적입니다.
위의 코드에서 첫 몇 행에 NaN이 생기는 이유가 있습니다. shift(1)을 하면 첫 번째 행은 가져올 "이전 값"이 없습니다.
rolling(window=3)을 하면 처음 두 행은 3개가 채워지지 않습니다. 이 NaN을 어떻게 처리할지 결정해야 합니다.
dropna()로 제거하거나, fillna()로 채우거나, min_periods 파라미터를 조정합니다. 실제 현업에서는 어떻게 활용할까요?
주식 분석에서 5일 이동평균선과 20일 이동평균선은 기본 지표입니다. 두 선이 교차하면 매매 신호로 봅니다.
수요 예측에서는 지난주 같은 요일 판매량을 피처로 사용합니다. 이상 탐지에서는 최근 평균 대비 편차로 비정상을 감지합니다.
주의할 점도 있습니다. **미래 정보 유출(Data Leakage)**을 조심해야 합니다.
예를 들어 shift(-1)은 다음 행의 값을 가져옵니다. 이걸 피처로 쓰면 모델이 미래를 보고 예측하는 셈이라 실전에서는 작동하지 않습니다.
또한 window 크기에 따라 결과가 크게 달라지므로 적절한 값을 실험으로 찾아야 합니다. 김개발 씨는 1일 전, 2일 전 주가와 3일 이동평균을 피처로 추가했습니다.
단순한 변수 추가만으로도 예측 정확도가 15% 향상되었습니다. 시차와 이동 변수는 시계열 분석의 필수 도구입니다.
과거에서 미래를 읽어내세요.
실전 팁
💡 - rolling에서 min_periods=1로 설정하면 NaN을 최소화할 수 있음
- 여러 window 크기(3일, 7일, 30일)를 함께 사용하면 다양한 스케일의 패턴 포착 가능
- expanding()은 누적 평균을 계산, 시작점부터 현재까지의 평균
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
Helm 마이크로서비스 패키징 완벽 가이드
Kubernetes 환경에서 마이크로서비스를 효율적으로 패키징하고 배포하는 Helm의 핵심 기능을 실무 중심으로 학습합니다. Chart 생성부터 릴리스 관리까지 체계적으로 다룹니다.
보안 아키텍처 구성 완벽 가이드
프로젝트의 보안을 처음부터 설계하는 방법을 배웁니다. AWS 환경에서 VPC부터 WAF, 암호화, 접근 제어까지 실무에서 바로 적용할 수 있는 보안 아키텍처를 단계별로 구성해봅니다.
AWS Organizations 완벽 가이드
여러 AWS 계정을 체계적으로 관리하고 통합 결제와 보안 정책을 적용하는 방법을 실무 스토리로 쉽게 배워봅니다. 초보 개발자도 바로 이해할 수 있는 친절한 설명과 실전 예제를 제공합니다.
AWS KMS 암호화 완벽 가이드
AWS KMS(Key Management Service)를 활용한 클라우드 데이터 암호화 방법을 초급 개발자를 위해 쉽게 설명합니다. CMK 생성부터 S3, EBS 암호화, 봉투 암호화까지 실무에 필요한 모든 내용을 담았습니다.
AWS Secrets Manager 완벽 가이드
AWS에서 데이터베이스 비밀번호, API 키 등 민감한 정보를 안전하게 관리하는 Secrets Manager의 핵심 개념과 실무 활용법을 배워봅니다. 초급 개발자도 쉽게 따라할 수 있도록 실전 예제와 함께 설명합니다.