LITTLE BY LITTLE

Pandas - 그룹 연산 본문

데이터 분석/파이썬 Basic & EDA

Pandas - 그룹 연산

위나 2022. 7. 12. 09:22

 

데이터를 집계하거나 변환할 때, 한번에 처리하기 위해서 split-apply-combine(분할-반영-결합) 과정을 거쳐야한다.

 

SQL의 GROUP BY 구문과 비슷하다.

from google.colab import files
myfiles = files.upload()
import pandas as pd
df = pd.read_csv('gapminder.tsv',sep='\t')
avg_life_exp_by_year = df.groupby('year').lifeExp.mean()
print(avg_life_exp_by_year)

 

분할 작업 : 먼저 데이터를 중복 없이 추출

years = df.year.unique()
print(years)

반영 작업 : loc을 이용, 1952년의 데이터를 추출

y1952 = df.loc[df.year == 1952, :]
print(y1952.head())

추출한 데이터의 평균 구하기 : 이 과정도 반영의 한 부분

y1952_mean = y1952.lifeExp.mean()
print(y1952_mean)


y1957 = df.loc[df.year == 1957, :]
y1957_mean = y1957.lifeExp.mean()
print(y1957_mean)

y1962 = df.loc[df.year == 1962, :]
y1962_mean = y1962.lifeExp.mean()
print(y1962_mean)

y2007 = df.loc[df.year == 2007, :]
y2007_mean = y2007.lifeExp.mean()
print(y2007_mean)

마지막으로 반영한 데이터를 다 합치는 "결합"작업

df2 = pd.DataFrame({"year":[1952, 1957, 1962, 2007],
                    "":[y1952_mean, y1957_mean, y1962_mean, y2007_mean]})
print(df2)

 


자주 쓰이는 집계 메소드

 

  1. count : 누락값 제외한 데이터 수 반환
  2. size : 누락값 포함한 데이터 수 반환
  3. mean, std, min
  4. quantile(q=0.25) , q=0.5, q=0.75
  5. max, sum, var
  6. sem : 평균의 표준편차 반환
  7. describe : 데이터 수, 평균, 표준편차, 최소값, 백분위수(25,50,75%), 최댓값 모두 반환
  8. first : 첫번째 행 반환
  9. last : 마지막
  10. nth: n번째 행 반환

agg메소드로 사용자 함수와 groupby메소드 조합하기

 

 

mean을 직접 함수로 만들 경우

def my_mean(values):
    n = len(values)
    sum=0
    for value in values:
        sum += value

        return sum / n
agg_my_mean = df.groupby('year').lifeExp.agg(my_mean)
print(agg_my_mean)

 

2개의 인자값을 받아 처리하는 사용자 함수 groupby 메소드

 

평균 차이 계산 함수 만들어보기

def my_mean_diff(values,diff_value):
    n = len(values)
    sum = 0
    for value in values:
        sum += value
        mean = sum / n
        return mean - diff_value

global_mean = df.lifeExp.mean()
print(global_mean)
agg_mean_diff = df.groupby('year').lifeExp.agg(my_mean_diff,diff_value = global_mean)
print(agg_mean_diff)

여러 집계 메소드 한번에 사용하기

 

딕셔너리에 담아 전달

import numpy as np
gdf = df.groupby('year').lifeExp.agg([np.count_nonzero,np.mean,np.std])
print(gdf)
gdf_dict = df.groupby('year').agg({'lifeExp':'mean','pop':'median','gdpPercap':'median'})
print(gdf_dict)

데이터 변환

 

 

데이터 변환 메소드에서는 데이터와 메소드를 일대일로 대응시켜 계산하기 때문에 데이터의 양이 줄어들지 않는다.

 

표준 점수 계산하기 (표준 점수란 평균과 표준편차의 차이)

 

표준 점수를 구하면 변환한 데이터의 평균은 0, 표준편차는 1이 된다. => 데이터가 표준화되어 서로다른 데이터를 쉽게 비교할 수 있게됨

def my_zscore(x):
    return(x-x.mean()) / x.std()

 

df.transform(함수) : transform메소드를 이용하여 my_zscore 함수 적용하기

# transform 예시
df3 = pd.DataFrame(np.array([[0,1,1,0],[0,1,0,1],[1,2,3,4]]),columns=['a','b','c','d'])
df3
# 위의 데이터프레임의 각 열에 대해서 모두 10을 더해서 새로운 데이터프레임 정의하기
df3_modified = df3.transform(func = lambda x:x+10)
df3_modified
# transform 다른 예시
# transform 사용 안했을 때 (groupby+merge사용) vs transform 사용했을 때 비교
# 실행x, 코드만 비교해보기, 목적은 "구매자들의 평균 구매내역 표 추출"

import pandas as pd
df.groupby('User_ID')["Purchse"].mean()
mean_purchase = df.groupby('User_ID')["Purchse"].mean().rename("User_mean").reset_index
df_1 = df.merge(mean_purchase)
df["User_Mean"] = df.groupby('User_ID')["Purchase"].transform('mean')

apply와 transform을 헷갈리지 말자.

 

apply()함수 사용시, 데이터프레임 전체 열의 값들을 조작하면서 값을 계산할 수 있다. <=>d를 계산하기위해서, abc열을 모두 계산할 수 있다.

 

반면에 transform()함수의 경우, 하나의 열 또는 행을 조작하는 것이지, 전체 데이터프레임을 한번에 연산하는 것이 불가능하다.

 

다시 예제로 돌아와서

transform_z = df.groupby('year').lifeExp.transform(my_zscore)
print(transform_z.head())
df.shape
transform_z.shape

- my_zscore 함수는 데이터를 표준화할뿐 집계는 하지 않기에, 데이터의 크기에는 변화가 없음을 확인할 수 있다.


누락값을 평균값으로 처리하기

 

 

seaborn 라이브러리의 tips 데이터에서 10개의 행데이터만 가져와서 total_bill 열의 값 4개를 임의로 누락값으로 바꿈

import seaborn as sns
import numpy as np
np.random.seed(42)

tips_10 = sns.load_dataset('tips').sample(10)
tips_10.loc[np.random.permutation(tips_10.index)[:4],'total_bill']=np.NaN
print(tips_10)

단순히 바로 NaN을 평균으로 채울 수 없다.

 

그 이유는 현재 tips_10의 데이터는 여성보다 남성이 많기 때문에, 원본 데이터에 영향을 주지 않고 결측치를 메꾸려면 여성과 남성을 구분해서 처리해야함

 

일단 먼저성별로 그룹화한 다음, 각 열의 데이터 수를 구해야한다.

count_sex = tips_10.groupby('sex').count()
print(count_sex)

그 다음 성별을 구분하여 total_bill 열의 데이터를 받아 평균값을 구해야한다.(함수 정의하기)

def fill_na_mean(x):
    avg = x.mean()
    return x.fillna(avg)

마지막으로 성별을 구분한 total_bil 열의 데이터를 fill_na_mean 함수에 전달하여 평균을 구한 후, tips_1o에 새로운 열로 추가하기.

total_bill_group_mean = tips_10.groupby('sex').total_bill.transform(fill_na_mean)
tips_10['fill_total_bill'] = total_bill_group_mean
print(tips_10)

데이터 필터링

 

 

그룹화한 데이터에서 원하는 데이터를 걸러내고 싶을 때.

 

데이터 필터링을 사용하면 기준에 맞는 데이터를 걸러낼 수 있다.

tips = sns.load_dataset('tips')
print(tips.shape)
print(tips['size'].value_counts()) #1,5,6 테이블 주문이 매우 적음을 알 수 있음

 

불균형 데이터 -> 제거하기

 

30번 이상의 주문이 있는 테이블만 추려서 데이터 분석하기

 

30번 이상의 주문이 있는 테이블만 그룹화하여 변수 tips_filtered에 저장

tips_filtered = tips.\
groupby('size').\
filter(lambda x: x['size'].count() >=30)
 
print(tips_filtered.shape)
 
print(tips_filtered['size'].value_counts())

그룹 오브젝트

 

tips_10 = sns.load_dataset('tips').sample(10,random_state=42)
print(tips_10)


grouped = tips_10.groupby('sex')
print(grouped)
# groupby 메소드의 결과값은 "object"임을 확인

 

 

df.groups

 

그룹 오브젝트에 포함된 그룹을 보려면 groups 속성을 출력하면 된다.

 

sex열로 그룹화한 데이터프레임의 인덱스를 확인할 수 있다.

 

이 그룹 오브젝트로 집계,변환,필터 작업을 수행하면 된다.

print(grouped.groups)

한번에 그룹 오브젝트 계산하기

 

mean을 계산할 수 없는 열이 포함되어있더라도 (ex. day, time) 그룹 오브젝트에 mean 메소드를 바로 사용해서 구할 수 있다. 알아서 계산가능한 열의 평균만 출력해줌

 

avgs = grouped.mean()
print(avgs)

get_group

 

 

그룹 오브젝트 활용하기 (추출,반복)

 

get_group : 그룹 오브젝트에서 특정 데이터만 추출하기

 
 
get_group을 이용하여 성별이 여성인 데이터만 추출
female = grouped.get_group('Female')
print(female)

 

그룹 오브젝트를 반복문에 사용해보기

 

sex열을 기준으로 그룹화한 tips 데이터 집합은 여성 그룹과 남성 그룹으로 나누어져 있다.

 

이 특징을 이용하여 반복문을 사용하면 된다.

for sex_group in grouped:
    print(sex_group)
for sex_group in grouped:
    print('the type is : {}\n'.format(type(sex_group)))
    print('the length is : {}\n'.format(len(sex_group)))
    
    first_element = sex_group[0]
    print('the first element is : {}\n'.format(first_element))
    print('it has a type of : {}\n'.format(type(sex_group[0])))


    print('what we have')
    print(sex_group)
    break
# 결과를 보면 sex_group으로 넘어온 값이 다 튜플이라는 것을 알 수 있다.
 

여러 열을 사용해 그룹 오브젝트 만들고 계산하기

 

열 이름이 담긴 리스트를 groupby 해주면 된다.

bill_sex_time = tips_10.groupby(['sex','time'])
group_avg = bill_sex_time.mean()

print(group_avg)
 
print(type(group_avg))
# 데이터프레임임을 알 수 있다.
 
print(group_avg.index)

 

위에서 확인한 결과 데이터프레임의 인덱스가 Multi index이다.

 

이런 경우에는 reset_index를 이용해서 데이터 프레임의 인덱스를 새로 부여할 수 있다.

group_method = tips_10.groupby(['sex','time']).mean().reset_index()
print(group_method)

 

reset_index 대신 as_index 인자를 False로 설정해도 위와 같은 결과를 얻을 수 있다.

group_param = tips_10.groupby(['sex','time'], as_index=False).mean()
print(group_param)

 

 

 
 
Comments