Grouping
PER 값에 따라 group number 부여하기
- 값을 기준으로 grouping 하기
1) boolean section(조건식) & loc 사용
df.shape
# (681, 17)
bound1 = df['PER(배)'] >= 10
# (378, 17)
bound2 = (5 <= df['PER(배)']) & (df['PER(배)'] < 10)
bound3 = (0 <= df['PER(배)']) & (df['PER(배)'] < 5)
bound4 = df['PER(배)'] < 0
df.loc[bound1, 'PER_Score'] = 1
df.loc[bound2, 'PER_Score'] = 2
df.loc[bound3, 'PER_Score'] = 3
df.loc[bound4, 'PER_Score'] = -1
df['PER_Score'].value_counts()
# 1.000 378
# 2.000 148
# -1.000 120
# 3.000 23
# Name: PER_Score, dtype: int64
nan 값을 체크 후, 다른 값으로 교체해야함.
df['PER_Score'].isna().sum()
# 12
df.loc[df['PER_Score'].isna(), "PER_Score"] = 0
# 아래와 같은 방식으로도 가능
# df['PER_Score'] = df['PER_Score'].fillna(0)
# df.loc[:, 'PER_Score'] = df['PER_Score'].fillna(0) - Pandas 권장 방식
nan 값을 체크 후, 다른 값으로 교체해야함.
nan 값을 0으로 메꾸었을 때의 문제점은 기존에 이미 존재하는 값 중에서 PER_Score이 0 인 값이 있다면, 임의로 메꾼 0과 구분할 수 없습니다. 따라서 데이터 값의 특성을 잘 반영해서 메꿀 값을 선택하는 것이 중요합니다.
2) Boolean Series의 연산 특성 사용
df.loc[:, "PER_Score1"] = (bound1 * 1) + (bound2 * 2) + (bound3 * 3) + (bound4 * -1)
df['PER_Score'].value_counts()
# 1 378
# 2 148
# -1 120
# 3 23
# 0 12
# Name: PER_Score1, dtype: int64
- bound1, bound2... True에 해당되면 n, False에 해당되면 0
- nan값은 결국 0만 남게 된다.
- 더 간결한 코드로 위와 같은 결과
.cut()
- 위의 기능과 동일한 Pandas 함수
- dtype : category [한국, 미국, 중국] 처럼 유한한 변수의 선택지
per_cuts = pd.cut(
df['PER(배)'],
[-np.inf, 0, 5, 10, np.inf],
)
per_cuts.head()
# 0 (10.0, inf]
# 1 (10.0, inf]
# 2 (5.0, 10.0]
# 3 (10.0, inf]
# 4 (10.0, inf]
# Name: PER(배), dtype: category
# Categories (4, interval[float64, right]): [(-inf, 0.0] < (0.0, 5.0] < (5.0, 10.0] < (10.0, inf]]
- cut()에 label 달아주기 可
bins = [-np.inf, 10, 20, np.inf]
labels = ['저평가주', '보통주', '고평가주']
per_cuts2 = pd.cut(
df['PER(배)'],
bins=bins,
labels=labels
)
per_cuts2.head()
# 0 보통주
# 1 고평가주
# 2 저평가주
# 3 보통주
# 4 고평가주
# Name: PER(배), dtype: category
# Categories (3, object): ['저평가주' < '보통주' < '고평가주']
'개체 수'를 기준으로 grouping 하기
- quantile : qcut()
- qcut() 함수를 이용해서 PER 그룹 나누기
- 분포를 n 등분 했을 때, 어느 구역에 할당되는지 표시해줌
df.loc[:, 'PER_Score2'] = pd.qcut(df['PER(배)'], 10, labels=range(1, 11))
df['PER_Score2'].value_counts()
# 1 67
# 2 67
# 3 67
# 4 67
# 5 67
# 7 67
# 8 67
# 9 67
# 10 67
# 6 66
# Name: PER_Score2, dtype: int64
df['PER_Score2'].isna().sum() # nan 체크
# 12
df = df.dropna(subset=['PER(배)']) # nan 제거
df['PER_Score2'].isna().sum()
# 0
Groupby & Aggregation : 데이터 준비
- Split - Apply - Combine
- groupby() : 실제로 grouping 까지는 하지 않고, grouping이 가능한지 validation만 진행(preparation)
- aggregation : columns + functions(sum, min, max, mean, count, variance, std..)
g_df_obj = g_df.groupby(["PBR_score", "PER_score"])
g_df_obj
#<pandas.core.groupby.generic.DataFrameGroupBy object at 0x00000183FC52AF10>
type(g_df_obj)
# pandas.core.groupby.generic.DataFrameGroupBy
g_df_obj.size().head()
# PBR_score PER_score
# 1 1 5
# 2 11
# 3 11
# 4 11
# 5 7
# dtype: int64
# Multi-level index를 가진 Series indexing하는 법
g_df_obj.size().loc[1]
g_df_obj.size().loc[(1, 1)]
aggregation
- 반드시 aggregating 기능이 있는 function을 써야함.
- 여러 값 -> 1개 값
- min, max, mean, median, sum, var, size, nunique, idxmax
g_df.groupby("PBR_score").agg(
{
"rtn": "mean", # = np.mean
}
)
# 다양한 방법으로 진행하기 (같은 결과)
# 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()
# 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']
}
)
g_df1 = g_df.groupby(["PBR_score", "PER_score"])\
.agg(
{
'rtn': ['mean', 'std', 'min', 'max'],
'ROE(%)': [np.mean, 'size', 'nunique', 'idxmax']
}
)
- nan은 groupby시 자동으로 filter out 되기 때문에, 미리 전처리 하는게 좋음
df = pd.DataFrame({
'a':['소형주', np.nan, '대형주', '대형주'],
'b':[np.nan, 2, 3, np.nan],
})
df.groupby(['a'])['b'].mean()
# a
# 대형주 3.000
# 소형주 NaN
# Name: b, dtype: float64
Multi-index columns를 하나로 병합하기
level0 = g_df1.columns.get_level_values(0)
level1 = g_df1.columns.get_level_values(1)
level0
level1
# Index(['rtn', 'rtn', 'rtn', 'rtn', 'ROE(%)', 'ROE(%)', 'ROE(%)', 'ROE(%)'], dtype='object')
# Index(['mean', 'std', 'min', 'max', 'mean', 'size', 'nunique', 'idxmax'], dtype='object')
g_df1.columns = level0 + '_' + level1
* 시가총액으로 Small and Big 나누기
median_df = a_df.groupby(['date']).agg({'시가총액 (보통)(평균)(원)': 'median'})
median_df.head()
median_df.columns = ['시가총액_median']
median_df.head()
'Quant' 카테고리의 다른 글
Quant : Visualization - Matplotlib (0) | 2022.04.13 |
---|---|
Quant : Pandas - 데이터 합치기 (0) | 2022.04.05 |
Quant : Pandas - API(2) (0) | 2022.03.15 |
Quant : Pandas - API (1) (0) | 2022.03.14 |
Quant : Pandas - Series & DataFrame (0) | 2022.03.12 |