2025. 12. 4. 20:46ㆍTIL
파이썬에서 Window Function을 이용할 수 있는 방법과, 다양한 변수들 간의 상관계수를 계산할 수 있는 방법
1. Python의 window function
1) SHIFT
시계열 데이터의 인덱스를 원하는 기간 만큼 땡기거나 미는 메서드 (SQL의 LAG와 LEAD)
df.shift(periods=기간, freq=None, axis=0, fill_value=None)
- periods : 이동할 기간. 음수 또는 양수를 입력
- freq : 선택 매개변수. 시계열 데이터에서 이동할 단위를 선택. Y, M, D, H, T, S, Timestamp, 'infer' 등이 위치
- infer는 시계열 데이터를 보고 자동으로 이동 단위를 결정함
df3_prac1['T_SHIFT1'] = df3_prac1['Time stamp'].shift(1)
df3_prac1['T_SHIFT-1'] = df3_prac1['Time stamp'].shift(-1)
2) ROLLING
데이터프레임 내 열에 대해서 일정 크기의 창(window)을 지정하여 그 window 안의 값을 추가 연산을 통해 계산하는 메서드
df.rolling(window=X, min_periods=None, center=False, win_type=None, on=None, axis=0, closed=None, method='single')
- window : 계산할 창의 크기 (열 기준으로 계산할 경우 행의 수)
- min_periods : 계산할 최소 크기. 기본적으로 window의 크기와 동일함
- center : 계산을 중간 행에서 할 지 결정하는 파라미터. 기본값은 False
- win_type : triang/gaussian 등 가중치를 넣어 계산할 때, 그 계산 방식
- on : 시계열 인덱스나, 시계열과 유사한 열이 있을 경우 이 열을 기준으로 rolling을 수행할 수 있다.
- axis : 연산할 축 방향 설정
- closed : 연산이 닫히는 방향을 설정 (left, right, both, neither)
- method : numba 라이브러리를 이용해 테이블 계산을 수행하여 속도를 높일지 여부. 현재 'single'만 사용 가능
merged_df = pd.merge(df3_prac2, df2, left_on='user id', right_on='Customer ID', how='inner')
merged_df = merged_df[['Customer ID', 'Purchase Amount (USD)', 'Time stamp']]
# groupby의 응용 연산 : 기준 컬럼에 대해 집계할 컬럼 별로 다른 연산을 하고 싶을 때
merged_df = merged_df.groupby(['Time stamp']).agg({'Customer ID':'count', 'Purchase Amount (USD)':'sum'}).reset_index()
merged_df2 = merged_df.copy()
# Rolling 메서드를 활용한 purchase amount 3일 이동평균 구하기
window_size = 3
merged_df['Moving Average'] = merged_df['Purchase Amount (USD)'].rolling(window=window_size).mean().round(1)
# 3일 이동평균을 중간 행을 기준으로 계산
merged_df['Moving Average2'] = merged_df['Purchase Amount (USD)'].rolling(window=window_size, center=True).mean().round(1)
# 3일 이동평균을 중간 행을 기준으로 계산하고, 왼쪽 값을 포함하여 계산
merged_df['Moving Average3'] = merged_df['Purchase Amount (USD)'].rolling(window=window_size, center=True, closed='left').mean().round(1)
# 3일 누적합 구하기
merged_df['prefix_sum'] = merged_df['Purchase Amount (USD)'].rolling(window=window_size).sum().round(1)
3) EXPANDING
행이나 열의 값에 대해 누적ㅇ로 연산을 수행하는 메서드
df.expanding(min_periods=1, axis=0, method='single').추가메서드()
- min_periods : 연산을 수행할 요소의 최소 개수
- axis : 연산할 축 방향 설정
- method : 연산 방식. single, table이 있으며, table을 사용하기 위해서는 numba 라이브러리를 추가로 import해야 함
merged_df["Cumulative Mean Purchase"] = merged_df["Purchase Amount (USD)"].expanding().mean()
merged_df["Cumulative Sum Purchase"] = merged_df["Purchase Amount (USD)"].expanding().sum()
2. DATA TYPE 별 상관관계 계산
df = pd.read_csv('articles_hm.csv')
df2 = pd.read_csv('customer_hm.csv')
df3 = pd.read_csv('transactions_hm.csv')
mdf = pd.merge(df2, df3, how='inner', on='customer_id')
mdf2 = pd.merge(mdf, df, how='inner', on='article_id')
# 범주형 변수의 범위 확인하기
mdf2['club_member_status'].unique()
mdf2['fashion_news_frequency'].unique()
mdf2['sales_channel_id'].unique()
1) Point-Biserial Correlation
연속형 변수와 이분형 범주형 변수 간의 상관관계를 계산하는 상관계수
이분형 변수를 0/1로 코딩한 다음 연속형 변수와 Pearson 상관계수를 계산
결과값은 -1 ~ 1 사이의 값을 가지며, 절대값이 1에 가까울수록 상관관계가 크다는 것을 의미함.
단순 검정통계량만 확인하는 것이 아니라, p-value를 함께 확인해 통계적으로 유의미한 값인지 검증해 봐야 함.
r, p_value = stats.pointbiserialr(mdf['sales_channel_id'], mdf['price'])
- r(상관계수)이 0.17 정도로 두 변수는 상관관계가 높지 않음을 알 수 있음.
- p-value가 0.05보다 작으므로, 해당 결과는 통계적으로 의미가 있다.
2) ANOVA 검정
연속형 변수와, 3개 이상의 범주를 가지는 범주형 변수 간의 상관관계를 분석하는 검정 방식
명목형 범주형 변수 (범주 간 순서가 없는 범주형 변수)에 대해, 연속형 변수의 평균이 범주형 변수에 따라 차이가 있는지 분석해 상관계수를 계산한다.
Category를 club_member_status의 unique 값들로 지정하고, 이를 모든 행에 적용해 필터링한 데이터셋에서 price 컬럼만 가져온다.
groups = [mdf2['price'][mdf2['club_member_status']==category] for category in mdf2['club_member_status'].unique()]
ANOVA 검정의 결과 해석
- F <1 : 무의미
- 1 <= F < 3 : 거의 무의미
- 3 <= F <10 : 경우에 따라 유의미
- 10 <= F < 50 : 유의미 (강한 차이)
- F > 50 : 거의 확실한 유의미 (아주 강한 차이)
- F >= 100 : 확실한 유의미 (매우 강한 차이)
F 값이 큰것만 확인하는 것이 아니라, 이를 통계적으로 설명 가능한 지 P-value 도 함께 봐야 한다.
F 값이 크게 나왔지만, P-value 가 0.05 보다 크다면, 통계적으로 의미가 없을 수 있음

계산 결과, F는 150 이상인데 p-value는 0이다.
따라서 클럽 멤버상태와 결제 금액은 매우 강한 상관관계가 있다.
3) Cramer's V
두 범주형 변수 간의 상관관계를 분석할 때 사용
Cramer's V 상관계수는 두 범주형 변수 중 하나의 변수가 3개 이상의 범위를 가지는 경우 사용할 수 있음
- 1단계 : 범주형 변수의 값들을 LabelEncoding
- 2단계 : 함수 정의
- 3단계 : 혼동행렬 생성
Cramer's V 상관계수는 0 ~ 1의 값을 가지며, 값이 클수록 높은 상관관계가 있음을 의미함
scipy 라이브러리와 sklearn 라이브러리로 구현할 수 있다
from scipy.stats.contingency import association
from sklearn import preprocessing
from scipy.stats import chi2_contingency
# 1단계 : Label Encoding
base_df = mdf2[['club_member_status', 'fashion_news_frequency']]
base_df = base_df.dropna() #범주형 변수이기 때문에 결측치를 반드시 삭제해줘야 한다 (대체도 안됨)
label = preprocessing.LabelEncoder()
data_encoded = pd.DataFrame()
for i in base_df.columns:
data_encoded[i] = label.fit_transform(base_df[i])
data_encoded.head()
data_encoded.groupby(['club_member_status']).count()
# 2 ~ 3단계 : 함수 정의 및 혼동행렬(confusion matrix) 생성
# Cramer's V 함수 정의 (공식이라써 쓰는 게 아니고 복사 붙여넣기 하면 된다)
def cramers_V(var1, var2):
crosstab = np.array(pd.crosstab(var1, var2, rownames=None, colnames=None))
stat = chi2_contingency(crosstab)[0]
obs = np.sum(crosstab)
phi2 = stat / obs
r, k = crosstab.shape
phi2corr = max(0, phi2 - (((k-1)*(r-1))/(obs-1)))
rcorr = r - ((r - 1)**2)/(obs - 1)
kcorr = k - ((k - 1)**2) / (obs - 1)
return np.sqrt(phi2corr / min((kcorr - 1), (rcorr - 1)))
# 혼동행렬 생성
rows = []
for var1 in data_encoded:
col = []
for var2 in data_encoded:
cramers = cramers_V(data_encoded[var1], data_encoded[var2])
col.append(round(cramers, 2))
rows.append(col)
cramers_results = np.array(rows)
data_encoded_df = pd.DataFrame(cramers_results, columns = data_encoded.columns, index = data_encoded.columns)
data_encoded_df
'TIL' 카테고리의 다른 글
| 251208_BootCamp Day 36_표준화와 정규화 (0) | 2025.12.08 |
|---|---|
| 251205_BootCamp Day 35_주간 회고 (1) | 2025.12.05 |
| 251203_BootCamp Day 33_머신러닝 기초 (2) (0) | 2025.12.03 |
| 251202_BootCamp Day 32_데이터프레임 구조 변형 (0) | 2025.12.02 |
| 251201_BootCamp Day 31_머신러닝 기초 (1) (2) | 2025.12.01 |