데이터 변환 및 이상치 처리
1️⃣ 이상치 (Outlier)
이상치는 사분위 범위(IQR, Interquartile Range)를 벗어난 값으로 정의됩니다.
데이터 분석 및 모델링의 신뢰성을 저해하므로 적절한 처리가 필요합니다.
1.1 이상치(Outlier)의 정의
- 이상치는 다음 범위를 벗어나는 데이터 포인트를 의미합니다.
- IQR (Interquartile Range) 정의:
$$ \text{IQR} = Q3 - Q1 $$
- 하한 경계값 (Lower Bound)
- 이상치 판단기준(최솟값)
- $Q1 - 1.5 \times \text{IQR}$
- 상한 경계값 (Upper Bound)
- 이상치 판단기준(최댓값)
- $Q3 + 1.5 \times \text{IQR}$
1.2 이상치 판단 기준
- 이상치(Outlier): 이 범위를 벗어난 값
- Q1 (1사분위수): 데이터 25% 지점
- Q3 (3사분위수): 데이터 75% 지점
- IQR (사분위범위): 데이터 중간 50%의 범위
- IQR 벗어나면 이상치(Anomaly Data)
1.3 박스 플롯에서의 이상치 표시 방식
- 박스(Box): Q1(25%) ~ Q3(75%) 사이의 값 (데이터의 50% 포함)
- 중앙값(Median, Q2): 박스 내부의 가로선
- 수염(Whiskers): 이상치를 제외한 데이터의 최대/최소값 연결
- 이상치(Outlier): 박스 플롯 바깥쪽의 점(●, x)으로 표시
1.4 IQR을 활용한 이상치 탐지 및 제거 코드 예제
# 이상치 탐지
Q1 = df["Ad Clicks"].quantile(0.25) # 1사분위수
Q3 = df["Ad Clicks"].quantile(0.75) # 3사분위수
IQR = Q3 - Q1 # IQR 계산
# 이상치 제거
df_filtered = df[(df["Ad Clicks"] >= Q1 - 1.5 * IQR) &
(df["Ad Clicks"] <= Q3 + 1.5 * IQR)]
print(df_filtered)
- quantile(): 사분위수를 계산하는 함수
- IQR: 데이터 중간 50%의 범위
- 이상치 제거: 1.5 * IQR을 기준으로 하한/상한 경계 설정
1.5 API 통신 중 발생할 수 있는 결측치
API 통신 중 발생하는 결측치는 데이터베이스에 다음과 같은 방식으로 저장될 수 있다.
- NULL 값으로 저장됨 (null 응답).
- 빈 문자열로 저장됨 ("" 응답).
- 0 또는 기본값으로 저장됨.
- 잘못된 데이터 형식으로 저장됨 (예: int 필드에 string).
- 필드 자체가 누락되어 NULL로 저장되거나 기본값으로 채워짐.
데이터베이스에서 결측치를 처리할 때는 다음과 같은 방법을 고려할 수 있다.
- NULL 값 변환: COALESCE() 함수를 사용하여 NULL 값을 기본값으로 변환.
- 데이터 타입 검증: API 응답 데이터를 저장하기 전에 데이터 타입을 변환 또는 검증.
- 기본값 설정: DEFAULT 값을 설정하여 필드가 NULL이 아닐 때 기본값을 자동 삽입.
2️⃣ 데이터 변환 (Data Transformation)
2.1 데이터 변환의 필요성
- 데이터 정제(Data Cleaning): 결측값, 이상치를 처리하여 신뢰성 있는 데이터 확보
- 데이터 표준화(Standardization): 분석 및 비교를 위해 일관된 데이터 형식 유지
- 특성 엔지니어링(Feature Engineering): 새로운 변수 생성으로 인사이트 도출
- 머신러닝 모델 준비(Model Preparation): 모델 학습을 위한 데이터 전처리
3️⃣ 데이터 변환 기법
3.1 결측값 처리 (Handling Missing Values)
- 결측값: 데이터의 정확도가 낮아지고 왜곡될 가능성 있음
- 처리 방법:
- 평균(Mean) 또는 중앙값(Median)으로 대체
- 결측값 삭제 (dropna())
- 최빈값(Mode)으로 대체
#결측치 확
missing_values_example = df_example.isnull().sum()
# 결측값을 평균(Mean)으로 대체
df.fillna(df.mean(), inplace=True)
# 중앙값(Median)으로 대체
df.fillna(df.median(), inplace=True)
# 최빈값(Mode)으로 대체
df.fillna(df.mode().iloc[0], inplace=True)
#복사해서 사용 시,
df = df.fillna(df.mean())
#숫자형 데이터에서 `NaN` 값을 해당 열의 평균값으로 대체함.
df.fillna(df.mean(numeric_only=True))
- 결측치 확인 : isnull() 함수는 데이터프레임(DataFrame) 또는 시리즈(Series)에서 결측치(NaN)를 확인하는 함수입니다. 결과는 각 값이 결측치인지(True) 또는 아닌지(False)를 나타내는 불리언(Boolean) 값으로 반환됩니다.
- inplace=True는 pandas에서 데이터프레임를 수정할 때, 원본 객체를 직접 변경하도록 설정하는 옵션, 그래서 warning이 뜰 수 있음그래서 데이터 베이스를 복제해서 사용하는게 나음.
- 평균 대체 vs. 중앙값 대체
방법 | 장점 | 단점 | 추천 상황 |
평균(Mean) 대체 | 데이터의 전체적인 대표값을 유지 | 이상치(극단값)가 있으면 왜곡될 가능성 있음 | 이상치가 적고 정규분포를 따르는 경우 |
중앙값(Median) 대체 | 이상치(극단값)의 영향을 받지 않음 | 정규분포를 따르는 경우, 평균보다 대표성이 떨어질 수 있음 | 이상치가 많은 경우 |
3.2 데이터 타입 변환 (Data Type Conversion)
- 문자열을 숫자로 변환 (예: "Yes"/"No" → 1/0)
- 날짜 데이터를 분석 가능하도록 변환
# 광고 시청 여부를 0과 1로 변환
df["Ad Viewed"] = ["Yes", "No", "Yes", "No", "Yes"]
df["Ad Viewed"] = df["Ad Viewed"].map({"Yes": 1, "No": 0})
# 문자열 데이터를 숫자로 변환
df["Ad Viewed"] = df["Ad Viewed"].map({"Yes": 1, "No": 0})
# 날짜 데이터 변환
df["Survey Date"] = pd.to_datetime(df["Survey Date"])
#광고시청여부 컬럼 생성하여 데이터 넣기(문자열)
#문자열 데이터를 0,1 숫자로 변환(map 메서드 이용)
#surveydate 컬럼 생성후 날짜형으로 데이터를 바꿔서 저장
3.3 범주형 데이터 변환 (Categorical Encoding)
- 레이블 인코딩(Label Encoding): 범주형 데이터를 숫자로 변환
- 원-핫 인코딩(One-Hot Encoding): 범주형 데이터를 여러 개의 이진(0/1) 컬럼으로 변환
from sklearn.preprocessing import LabelEncoder
# 레이블 인코딩
le = LabelEncoder()
df["Campaign_Encoded"] = le.fit_transform(df["Campaign"])
# 원-핫 인코딩
df_one_hot = pd.get_dummies(df, columns=["Campaign"])
예제
import pandas as pd
import numpy as np
from sklearn.preprocessing import LabelEncoder # 머신러닝을 위한 레이블 인코딩 모듈 (범주형 데이터를 숫자로 변환)
# 📌 1. 예제 데이터 생성 (결측값 포함)
data = {
"User ID": [101, 102, 103, 104, 105], # 고유한 사용자 ID
"Age": [25, 30, np.nan, 40, 35], # 사용자의 나이 (결측값 포함)
"Ad Clicks": [10, 50, 35, 30, 60], # 광고 클릭 수
"Conversion Rate": [0.02, 0.05, 0.03, 0.04, 0.07], # 전환율 (클릭 후 구매 비율)
"Ad Influence": [5, np.nan, 3, 4, 5], # 광고 영향력 (결측값 포함)
"Product Satisfaction": [np.nan, 4, 3, 5, 4], # 제품 만족도 (결측값 포함)
"Campaign": ["YouTube Ad", "SNS Ad", "Search Ad", "Email Marketing", "SNS Ad"] # 광고 캠페인 유형
}
# 데이터를 pandas DataFrame으로 변환
df = pd.DataFrame(data)
# 📌 2. 결측값(NaN)을 각 컬럼의 평균값으로 대체 (숫자형 데이터에 대해서만)
df.fillna(df.mean(numeric_only=True), inplace=True)
# 📌 3. 레이블 인코딩(Label Encoding) - 범주형 데이터를 숫자로 변환
# - "Campaign" 열의 문자열 값을 숫자로 변환하여 새로운 컬럼 "Campaign_Encoded" 생성
le = LabelEncoder() # LabelEncoder 객체 생성
df["Campaign_Encoded"] = le.fit_transform(df["Campaign"]) # "Campaign" 열을 숫자로 변환
# 📌 4. 원-핫 인코딩(One-Hot Encoding) 적용 - 범주형 데이터를 0,1로 변환
# - "Campaign" 열을 원-핫 인코딩하여 새로운 컬럼 추가 (ex. Campaign_YouTube Ad, Campaign_SNS Ad 등)
df_one_hot = pd.get_dummies(df, columns=["Campaign"])
# 📌 5. 최종 결과 출력
print(df_one_hot)
정규화 예제 중,
📌 왜 "YouTube Ad"가 2고, "SNS Ad"가 1일까?
LabelEncoder()는 내부적으로 알파벳 순서(A → Z) 로 정렬한 후, 0부터 차례대로 숫자를 매김.
- 원-핫 인코딩(One-Hot Encoding)
- 범주형 데이터를 0과 1의 이진값으로 변환.
- 예: "Campaign" 컬럼이 "YouTube Ad", "SNS Ad", "Search Ad" 등의 값을 가진다면,이를 "Campaign_YouTube Ad", "Campaign_SNS Ad", "Campaign_Search Ad" 같은 새로운 컬럼으로 나눠 0 또는 1로 표시함.
- 장점: 모델이 범주 간 크기 차이를 인식하지 않도록 해줌.
- 레이블 인코딩(Label Encoding)
- 범주형 데이터(문자열)를 숫자로 변환함.
- 예: "YouTube Ad" → 2, "SNS Ad" → 1, "Search Ad" → 3, "Email Marketing" → 0
- 단점: 숫자의 크기가 의미를 가지므로(서열 관계로 해석될 수 있음) 머신러닝 모델에 따라 부적절할 수 있음.
📌 레이블 인코딩과 원-핫 인코딩 비교
- 레이블 인코딩: Campaign을 하나의 숫자 컬럼(0, 1, 2 등)으로 변환
- 원-핫 인코딩: Campaign을 여러 개의 컬럼으로 변환하여 0, 1 값으로 표시
3.4 데이터 스케일링 (Data Scaling)/ 정규화(Normalization) & 표준화(Standardization)
광고 영향도(Ad Influence), 제품 만족도(Product Satisfaction) 등 연속형 변수는 범위가 다를 수 있다.
따라서 모델 학습과 비교를 위해 정규화(Normalization) 또는 표준화(Standardization) 적용이 필요하다.
- 정규화(Normalization): 데이터를 0과 1 사이의 값으로 변환
- 표준화(Standardization): 평균 0, 표준편차 1의 정규 분포 형태로 변환
from sklearn.preprocessing import MinMaxScaler, StandardScaler
# 정규화 (Min-Max Scaling)
scaler = MinMaxScaler()
df_normalized = pd.DataFrame(scaler.fit_transform(df), columns=df.columns)
# 표준화 (Z-score Scaling)
scaler = StandardScaler()
df_standardized = pd.DataFrame(scaler.fit_transform(df), columns=df.columns)
fit_transform()은 데이터 학습(fit) + 숫자로 변환(transform)을 한 번에 수행하는 함수
3.5. 피처 엔지니어링 (Feature Engineering)
그로스 마케팅에서는 기존 데이터를 가공하여 새로운 인사이트를 얻을 수 있는 변수를 추가하는 것이 중요하다.
예를 들어, 만족도 점수를 기반으로 고객을 그룹화할 수 있다.
# 제품 만족도 점수가 4 이상이면 "High", 그렇지 않으면 "Low"
df["Satisfaction Level"] = df["Product Satisfaction"].apply(lambda x: "High" if x >= 0.8 else "Low")
print(df)
- if는 정규로 안해도 되고 인라인으로 써도됨.(함수내에)
3.5 로그 변환 (Log Transformation)
- 설명: 값이 극단적으로 큰 경우, 로그 변환을 사용하여 데이터를 안정화
- 사용 예시: 광고 비용, 매출액 등 지수 함수 형태의 데이터를 정규화
import numpy as np
# 로그 변환 적용 (0 방지 위해 1 추가)
df["Log Ad Cost"] = np.log1p(df["Ad Cost"])
3.6 날짜 데이터 변환 (Date Processing)
- 날짜 데이터를 연/월/일/요일 등으로 분해하여 분석 가능
- 시간에 따른 트렌드 분석이나 요일별 패턴 확인에 유용
# 날짜 데이터 추가
df["Date"] = pd.to_datetime(["2024-02-01", "2024-02-02", "2024-02-03", "2024-02-04", "2024-02-05"])
# 요일 컬럼 추가
df["Day of Week"] = df["Date"].dt.day_name()
--------------------------------------------
# 날짜 데이터 변환
df["Date"] = pd.to_datetime(df["Date"])
# 요일 추가
df["Day of Week"] = df["Date"].dt.day_name()
# 연도, 월, 일로 나누기
df["Year"] = df["Date"].dt.year
df["Month"] = df["Date"].dt.month
df["Day"] = df["Date"].dt.day
4️⃣그로스 마케팅에서 활용되는 데이터 변환 예시
그로스 마케팅에서는 고객 행동 데이터, 광고 성과 데이터, 전환율 분석 데이터 등 다양한 유형의 데이터를 다룬다.
효과적인 분석과 모델링을 위해 데이터 변환을 수행해야 하며, 다음과 같은 변환 기법이 활용된다.
- 결측값 처리 → 광고 클릭, 전환율 등 데이터 손실 방지
- 데이터 변환 → 숫자 변환, 인코딩, 로그 변환 등을 활용하여 비교 가능하게 변환
- 스케일링 적용 → 정규화 및 표준화를 통해 광고 비용, 클릭 수 등의 비교 가능
- 피처 엔지니어링 → 고객 세그먼트, 날짜 기반 변수 등을 추가하여 분석력 향상
- 이상치 제거 → 광고 효과 분석의 정확성을 높이기 위해 극단값 조정
'STUDY' 카테고리의 다른 글
[멋쟁이사자처럼부트캠프_그로스마케팅] Day 14 EDA, EDA 데이터 전처리 종합 실습 (0) | 2025.03.05 |
---|---|
[멋쟁이사자처럼부트캠프_그로스마케팅] Day 13-2 데이터 표준화, 정규화 (0) | 2025.02.26 |
[멋쟁이사자처럼부트캠프_그로스마케팅] Day 12 Matplotlib, Seaborn (0) | 2025.02.21 |
[멋쟁이사자처럼부트캠프_그로스마케팅] Day 11 API, Flask (6) | 2025.02.20 |
[멋쟁이사자처럼부트캠프_그로스마케팅] Day 10 웹 애플리케이션 구조, Flask, 웹크롤링 (1) | 2025.02.19 |