class="layout-aside-right paging-number">
본문 바로가기
데이터 분석/Python

Shift, Rolling, Expanding / 피어슨 상관계수, Point-Biserial Correlation, Anova 검정, Cramer's V

by heestory323 2025. 4. 4.

SQL의 window Function : 행과 행 간의 관계 정의. 순서, 집계, 순서, 비율

 

 

SHIFT

시계열 데이터의 인덱스를 기준으로 데이터/값을 원하는 방향으로 이동시키는(shift) 메서드

DataFrame.shift(periods=기간, freq=, axis=0, fill_value='비었음')

  • 주요 파라미터
    • periods: 이동할 기간(칸). 음수 또는 양수로 입력. 
                   +1 미래로, n만큼 이전 행을 뒤로 미는것  df.shift(1)
                    -1 과거로, 미래 행을 앞으로 땡겨오는 것  df.shift(-1)
    • freq: 선택 매개변수.날짜 단위로 이동
               Y년, M월, D일, H시, T분, S초, Timestamp, 'Infer'자동으로 적당하게 분석 등이 위치
    • fill_value: shift로 인해 생긴 결측치의 대체값 지정
    • axis: 연산할 축방향 설정. 0(행) / 1(열)
  • df.shift(1).head()  #뒤의 날짜의 데이터를 미래로 이동 (이전 값을 뒤로 한칸 밀기)
  • df.shift(-1).head() # 앞의 날짜의 데이터를 과거로 이동(이후 값들을 앞으로 한칸 땡기기)
  • df.shift(periods=3,freq='D') # 3일 이동
  • df.shift(periods=3,freq='infer') # df의 날짜간격을 분석해서 적당한 주기를 이동

 

 

Rolling - 시계열 데이터, 이동평균

여러개의 데이터가 시간순으로 있을 때, 특정기간(window, 범위)안의 값으로 추가 연산하여 계산하는 메서드

이동평균, 이동합 등 구할때 사용

-> 시간에 따른 데이터의 "추이"를 계속 이동하면서 확인할 수 있음(트렌드 파악)
   : 주가데이터, 날씨 데이터, 판매량 데이터 etc

 

DataFrame.rolling(window, min_periods=None, center=False, win_type=None, on=None, axis=0, closed=None, method='single').추가메서드()

  • 나(인덱스)를 포함(1) + 앞의 컬럼 (window size-1)개를 가져와서 계산 : closed=right(기본값)
  • 주요 파라미터
    • window: 계산할 창(window)/기간/구간의 크기. 열 기준으로 계산할 경우 행의 수 / 날짜 데이터의 경우 '일' 
    • min_periods: 계산할 최소 크기(기간) . 기본적으로 window 크기와 동일.
    • center: 계산을 중간 행에서 할 지 결정하는 파라미터. 기본값 False(창의 마지막 값을 기준으로 계산)
                   True 로 할 경우 창의 중앙값을 기준으로 계산(더 균형잡힌 방식으로 배치 가능)
    • win_type: triang / gaussian 등 가중치를 넣어 계산할 경우 계산 방식.
    • on: 시계열 인덱스나, 시계열과 유사한 열이 있을 경우 이 열을 기준으로 rolling을 수행할지 설정
    • axis : 계산할 방향  0(행) / 1(열)
    • closed: 연산이 닫히는 방향을 설정(경계값 포함여부) left / right / both / neither 
      • right: 오른쪽 값을 포함하여 계산 = 현재를 포함한 window size 개의 계산
      • left: 왼쪽 값을 포함하여 계산 = 현재을 제외하고 앞 window size 개의 계산
      • both: 양쪽을 포함하여 계산= window size만큼 현재 행 + 양쪽(앞뒤/왼오른쪽) 모두 포함하여 계산
      • neither: 양쪽을 포함하지 않고 계산 = 현재 행 + 양쪽값(앞뒤) 모두 제외 -> 그냥 다 NaN
    • method:{'single' / 'table'} numba를 이용하여 테이블 계산을 진행하여 속도를 높힐지 여부. 현재 'single'만 사용가능.
📌 핵심 원리
1. **window 크기(기간)**를 설정한다.
2. 데이터의 앞에서부터 순차적으로 window 크기만큼의 값들을 가져와 평균을 계산한다.
3. 결과를 새로운 컬럼에 저장한다.

df['이동평균'] = df['컬럼명'].rolling(window=창크기).mean()
  • 예시
    • df.rolling(window=3).mean() # 3일 이동평균 구하기
      기본 rolling은 창의 마지막 값을 기준으로 (앞의 n-1개의 행과 합쳐서) 이동평균을 계산.
           -> 그래서 맨 앞의 행에 NaN이 뜸 (맨앞에 행에는 더 앞의 값이 없으니까)
    • df.rolling(window=3, center=True).mean() #3일 이동평균을 중간행을 기준으로 계산
      3일의 이동평균이 해당 중간행을 기준으로 (양옆 행을 가져와) 계산
    • df.rolling(window=3).sum() # 3일 누적합 구하기
    • df.rolling(window=3, center=Ture, closed='left').mean() # 3일 이동평균을 중간 행을 기준으로 계산하고, 왼쪽 값을 포함하여 계산

 

Expanding - 누적합, 누적평균

행이나 열의 값에 대해 누적으로 연산을 수행하는 메서드

처음부터 해당 행(열)까지 모든 값을 포함하여 계산, 점점 커짐

df.expanding(min_periods=1, axis=0, method='single').추가메서드()

  • 주요 파라미터
    • min_periods: 연산을 수행할 요소의 최소 갯수. 이보다 작으면 NaN을 출력
    • axis : 연산할 축방향 설정. 0(행) / 1(열)
    • method: 연산방식. single(연산을 한 줄씩 수행) table(전체 테이블에 대해서 롤링수행).
                     기본값 single , 롤링 연산할 경우 numba 라이브러리 추가로 import 필요.
  • 예시
    • df.expanding(axis=1).sum() #열 기준으로 누적합 계산
    • df.expanding().mean() #첫 행부터 현재 행까지의 평균을 계산

 

 

데이터타입별 상관관계

상관관계 : 두 변수간의 직선관계

상관계수 : -1 ~ 1 사이의 값

+1에 가까울수록 양의 상관관계(비례)

0 에 가까울수록 선형적인 관계가 아님

- 1에 가까울 수록 음의 상관관계(반비례)

 

****상관관계는 인과관계(원인과 결과)와 다름!!!!! ****

 

 

상관계수 r : 변수간의 관계(선형 상관관계)의 강도를 나타내는 값
p-value : 해당 상관관계가 우연히 발생했을 확률(유의확률)               
                p-value<0.05 이면 "진짜 관계가 있다!" 라고 확신 가능 = 유의미한 관계라고 판단 가능

=> 상관계수만 보면 "강한 관계"로 보이지만, 실제로는 우연일 수 있음
      p-value가 작아야 "진짜 관계"라고 확신 가능
=> 상관계수 r + p-value를 함께 봐야 신뢰할 수 있는 분석이 가능 !!!!!!! 

 

연속형 - 연속형 : 피어슨 상관계수

결과값 : -1 ~ +1 사이

상관계수(절대값) r 해석
0.9 ~ 1.0 매우 높은 음/양의 상관관계
0.7 ~ 0.9 높은 음/양의 상관관계
0.5 ~ 0.7 약한 음/양의 상관관계
0.0 ~ 0.5 거의 상관관계가 없음

 

 

 

#### 파이썬 코드 #####

#피어슨 상관계수 계산
correlatioin = df.corr(method='pearson')
print(correlation)

 

 

 

상관계수 1.0 = 강한 상관계수 =  customer_zip_code_prefix 과 customer_zip_code_prefix 은 같음

 

 

 

연속형 - 범주형(이분형) : Point-Biserial Correlation - 0/1 변환 + 피어슨 상관계수

이분형 변수를 0/1로 코딩한 뒤-> 피어슨 상관계수로 계산 = Point-Biserial Correlation 

 

##### 파이썬코드 ####

python scipy 라이브러리의 pointbiserialr 함수를 이용

r, p_value = stat.pointbiserialr(변수1,변수2)

 

주의점: 연속형 변수와 범주형 변수에 대한 상관관계를 해석할 때에는,

단순 통계량(r)만 확인하는 것이 아닌, p-value(통계적으로 설명 가능한지) 를 함께 살펴봐야함.

 

# r = 0.17 이므로 상관관계가 없고, 이 통계는 p-value가 0.05보다 작으므로 통계적으로 신뢰성을 가짐.(유의미함)

 

 

연속형 - 범주형(3개 이상) : ANOVA 검정

범주형 변수가 명목형(순서x 범주형 변수)일 때, 범주형 변수에 따라 연속형 변수의 평균에 얼마나 차이가 있는지 검정

 

c.f 연속형-범주형 변수일때(2개), 두 그룹의 평균에 얼마나 차이가 있는지 비교 = t-검정

t-test(t-검정) 결과값 #p-value 로 평가 가능

 

결과값 -1 ~ +1

상관계수(절대값) 해석
0.9 ~ 1.0 매우 높은 음/양의 상관관계
0.7 ~ 0.9 높은 음/양의 상관관계
0.5 ~ 0.7 약한 음/양의 상관관계
0.0 ~ 0.5 거의 상관관계가 없음

 

ANOVA 검정 = 범주형 변수에 따라 연속형 변수의 평균 차이를 검정하는 방법 
                     = 1. 범주형 변수를 기준으로 데이터를 나누고, 
                        2. 그에 따른 연속형 변수의 평균 차이를 비교해야함

 

##### 파이썬코드 ####

 

 

1. 범주형 변수를 기준으로 연속형 변수를 나누고, 

groups = [df['price'][df['club_member_status'] == category] for category in df['club_member_status'].unique()]

   3. 필요한 값(연속형변수)       2.카테고리와 같은 행만 필터링         4.반복문for         1.범주형 변수에 존재하는 고유값(카테고리)

: 카테고리를 status(범주형변수)의 unique 값들로 지정하고, 이를 모든 행에 적용(for문), 결과적으로 필터링 된 데이터셋 중에서 price 컬럼만 가져오는 코드

 

2. 그에 따른 연속형 변수의 평균 차이를 비교해야함

python scipy 라이브러리의 f_oneway 함수

f_stat, p_value = stats.f_oneway(변수1,변수2,변수3)

 

-> ANOVA 검정을 통해, ##  F-Statistic, p-value 도출

검정통계량(F)  해석
F <1 무의미
1 <= F < 3 거의 무의미
3 <= F <10 경우에 따라 유의미
10 <= F < 50 유의미(강한차이)
F > 50 거의 확실한 유의미(아주 강한차이)
F >= 100 확실한 유의미(매우 강한차이)

 

주의점: 연속형 변수와 범주형 변수에 대한 상관관계를 해석할 때에는,

단순 통계량(r)만 확인하는 것이 아닌, p-value(유의확률,  통계적으로 설명 가능한지) 를 함께 살펴보아야 합니다.

 

# F= 150 -> 확실한 유의미
               -> 클럽멤버상태(범주형변수)에 따라서 나눠진 
그룹 price의 평균의 차이가 크다. = 통계적으로 설명 가능하다

 

 

 

범주형 - 범주형 : 파이 상관계수( Cramer's V )

범주형 변수(명목형)끼리 상관관계 확인하기

 

방법 : 두 범주형 변수를 0과 1로 코딩(숫자로 변환) → Pearson 상관계수를 구하기

각 범주형 변수는 2가지 값을 가지는 경우(이분형 변수) + 명목형(순서가 없는 범주) 여야 함.

  • Cramer's V 계수 : 두 범주형 변수 중 하나의 변수가 3개 이상의 범위를 가지는 경우 사용
    • step1. 범주형 변수의 값들을 LabelEncoding = 범주형 변수들이 연속형 변수(숫자형태)로 바꼈음
      • Encoding : 범주형 변수-> 수치형변수로 바꿔주기
      • LabelEncoding : 문자열의 unique값 -> 숫자로 바꿔줌 (하나씩) (mapping 개념)
      • one hot encoding : 목록화 한 후 목록값(속성)에 이진값(0/1) 할당
      • 다중 공선성 문제로 머신러닝시 조심해야함
    • step2. define a function
    • step3. 혼동행렬 생성
def cramers_V(var1,var2) :
    crosstab =np.array(pd.crosstab(var1,var2, rownames=None, colnames=None)) # Cross table building
    stat = chi2_contingency(crosstab)[0] # Keeping of the test statistic of the Chi2 test #빈도표
    obs = np.sum(crosstab) # Number of observations
    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]) # Cramer's V test
        col.append(round(cramers,2)) # Keeping of the rounded value of the Cramer's V  
    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

 

  •  Cramer's V 계수는 0과 1 사이의 값으로 나타남.
Cramer's V  계수(0~1) 계수 해석
0 - 0.1 무시해도 되는 관계
0.1 - 0.2 약한 상관관계
0.2 - 0.4 보통의 상관관계
0.4 - 0.6 약한 상관관계
0.6 - 0.8 강한 상관관계
0.8 - 1.0 매우 강한 상관관계

 

Cramer's V 계수는 python scipy 라이브러리와 sklearn 라이브러리로 구현

# 히트맵 그래프