본문 바로가기

Python/Pandas

Pandas _ qcut(균할분등) & groupby()

이번 포스팅은 Pandas를 이용한 데이터 분석을 할 때, 균할분등 혹은 그러한 작업 또 다른 그룹을 생성할 때 많이 사용되는 메소드를 소개한다.

 

 


#%%

import numpy as np
import pandas as pd

from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

pd.set_option('display.float_format', lambda x: '%.3f' % x)
pd.set_option('max_columns', None)

df = pd.read_csv()

#%%

#1. qcut <-Group내 데이터 갯수를 기준으로 Grouping(SAME number of members in each group)
pd.qcut(df['PER(배)'], 3, labels=[1,2,3]) #PER기준으로 정확히 3등분

df.loc[:, "PER_Score2"] = pd.qcut(df['PER(배)'], 10, labels = range(1,11))
df.head()

df['PER_Score2'].value_counts()
df['PER_Score2'].hasnans
df['PER_Score2'].isna().sum()
df['PER_Score2'].dtype #'category' type: A string variable consisting of only a few different values

df = df.dropna(subset=['PER(배)'])
df['PER_Score2'].isna().sum()
#%%
#2. Split - Apply - Combine

# NA값 제거
df = pd.read_csv()
df = df.dropna()
g_df = df.copy()
g_df.head()

# Group생성
g_df['rtn'] = g_df['price2'] / g_df['price'] -1
g_df.loc[:,'PER_score'] = pd.qcut(g_df['PER(배)'], 10, labels = range(1, 11))
g_df.loc[:,'PBR_score'] = pd.qcut(g_df['PER(배)'], 10, labels = range(1, 11))

g_df.set_index('ticker', inplace=True)

# groupby() & aggreation
# groupby의 경우 실제 그룹을 생성하지 않고, 그룹이 생성될 수 있는지 확인하는 정도가지

# 3. groupby object 살펴보기
g_df.groupby('PER_score')
g_df_obj = g_df.groupby(['PBR_score', 'PER_score'])
g_df_obj
g_df['PBR_score'].nunique()
g_df['PER_score'].nunique()

type(g_df_obj.size())
g_df_obj.size().head()

# Multi-level index를 가진 Series indexing하는 법 
g_df_obj.size().loc[1]
g_df_obj.size().loc[(1,1)]

type(g_df_obj.groups)
g_df_obj.groups.keys()
g_df_obj.groups.values()

for name, group in g_df_obj:
    print(name)
    group.head(2)
    
# 4. aggreggation (반드시 aggregating 기능이 있는 함수를 써야함) <- aggregation 함수가 아닌 경우에는 error 발생시킴
### 주의: nan은 groupby시 자동으로 filter out 되기 때문에, 미리 전처리 다 하는게 좋음 
g_df.groupby('PBR_score').agg(
    {
         "rtn" : "mean" # = np.mean
     }
    )
pbr_rtn_df = g_df.groupby("PBR_score").agg({"rtn" : "mean"})
per_rtn_df = g_df.groupby("PER_score").agg({"rtn" : "mean"})

pbr_rtn_df.head()

# 다양한 방법으로 진행하기 (같은 결과)
g_df.groupby("PER_score")['rtn'].agg('mean').head()
g_df.groupby("PER_score")['rtn'].agg(np.mean).head()
g_df.groupby("PER_score")['rtn'].mean().head()

# return type이 다를 수 있음에 주의
g_df.groupby("PER_score")['rtn'].agg("mean").head(2)   # Series로 return
g_df.groupby("PER_score")[['rtn']].agg("mean").head(2)  # DataFrame으로 return

# 2개 이상의 컬럼에 대해 aggregation
g_df.groupby('PER_score')[['rtn', 'PBR(배)']].agg("mean").head(2)

# 2게 이상의 aggregation
g_df.groupby("PER_score")[['rtn', 'PBR(배)']].agg('mean','std').head(2)

# 2개 이상의 컬럼 & 각각에 대해 다른 aggregation
g_df.groupby("PBR_score").agg(
    
    {
     'rtn' : ['mean', 'std'],
     'PER(배)' : ['min']
     
     }    
)
pbr_rtn_df.plot(kind = "bar")
per_rtn_df.plot(kind = "bar")

a = g_df.groupby(["PBR_score", "PER_score"])['rtn', 'ROE(%)'].agg(['sum', 'mean'])

###  `as_index = False` : group cols들이 index가 아니라 하나의 col이 됨 (aggregate하고 reset_index()를 취한 것)
a = g_df.groupby(["PER_score"]                ).agg({'rtn': ['mean', 'std']}).head(2)
b = g_df.groupby(["PER_score"], as_index=False).agg({'rtn': ['mean', 'std']}).head(2)

a.index
a.columns
b.index
b.columns

### Multi-index columns을 하나로 병합하기
g_df1 = g_df.groupby(["PBR_score", "PER_score"])\
            .agg(
                {
                    'rtn': ['mean', 'std', 'min', 'max'],
                    'ROE(%)': [np.mean, 'size', 'nunique', 'idxmax'] 
                 }
            )
g_df1.head()

level0 = g_df1.columns.get_level_values(0)
level1 = g_df1.columns.get_level_values(1)

g_df1.columns = level0 + '_' + level1
g_df1

g_df1 = g_df1.reset_index()