[판다스] groupby 관련 메서드

밍키·2020년 8월 14일
0

판다 판다 판다스

목록 보기
10/12

1. filter


1.1 filter(함수, **kwargs)


  • DataFrameGroupBy.filter(func, dropna=True, *args, **kwargs)
  • 특정 집계 조건을 만족하는 Group의 원소들만 조회한다.
    1. DataFrameGroupBy 를 함수에 전달한다.
    2. 함수는 받은 DataFrameGroupBy로 집계를 한 뒤 원하는 조건을 비교한다.
    3. 그 조건을 만족하는 Group의 값들로 구성된 DataFrame을 반환한다.
  • 매개변수
    • func: filtering할 함수
      • 첫번째 매개변수로 Group으로 묶인 DataFrame을 받는다.
    • dropna=True
      • 필터를 통과하지 못한 group의 DataFrame의 값들을 drop시킨다. False로 설정하면 NA 처리해서 반환한다.
    • 함수:첫번째 매개변수로 Series 또는 DataFrame을 받아 특정 조건(주로 집계결과관련) 확인해 boolean값을 반환하는 함수
    • args, kwargs: filter 함수의 매개변수에 전달할 전달인자값.

1.2 과일 중, cnt1의 평균이 20 이상인 과일들만 보기


집계결과가 아니라 값들을 다 출력

# cnt1 - 사과: 10대, 귤: 20대, 배: 단단위, 딸기 30이상
data = dict(fruits=['사과', '사과','사과', '사과','사과','귤','귤','귤','귤','귤','배','배','배','배','배','딸기','딸기','딸기','딸기','딸기']
            ,cnt1=[10, 12, 13, 11, 12, 21, 22, 27, 24, 26, 7, 7, 8, 3, 2, 30, 35, 37, 41, 28]
            ,cnt2=[100,  103, 107, 107,  101,  51,  57, 58,  57, 51,  9, 9,  5,  7,  7,  208, 217, 213, 206, 204]
           )
df = pd.DataFrame(data)
df

df['fruits'].unique()

# 1
r = df.groupby('fruits')['cnt1'].mean()
r

# 2
r>=20

# 3
r[r>=20]

# 단순히 집계 결과가 아니라 데이터를 다 보고싶다.
# 귤과 딸기의 전체 데이터를 다 보겠다
# 그룹의 원소 데이터를 다 보겠다
# 그 때 필터를 쓴다.

def check_mean1(x):
    '''
    [매개변수]
        x : DataFrame - groupby에 의해 그룹핑된 DataFrame들 하나하나를 받는다.
    [반환값]
        boolean : cnt1의 평균이 20 이상인지 여부를 반환.
    '''
    return x['cnt1'].mean() >= 20
    
# 필터 사용하기
df.groupby('fruits').filter(check_mean1)
# 이 조건을 만족하는 데이터를 보고싶은 것.
# 데이터 전체를 다 보고싶은 것.

# dropna
df.groupby('fruits').filter(check_mean1, dropna=False)
# NA로 반환해준다.

2. transform


2.1 transform()


  • 기본 개념
    • 함수에 의해 처리된 값(반환값)으로 원래 값들을 변경(tranform) 해서 반환
    • DataFrame에 Group 단위 통계량을 추가할 때 유용하다.
  • 구문
    • DataFrameGroupBy.transform(func, *args)
    • SeriesGroupBy..transform(func, *args)
      • func: 매개변수로 그룹별로 Series를 받아 Series의 값들을 변환하여 (Series로)반환하는 함수객체
      • DataFrameGroupBy은 모든 컬럼의 값들을 group 별 Series로 전달한다.
      • *args : 함수에 전달할 추가 인자값이 있으면 매개변수 순서에 맞게 값을 전달한다. (위치기반 argument)
  • transform() 함수를 groupby() 와 사용하면 컬럼의 각 원소들을 자신이 속한 그룹의 통계량으로 변환된 데이터셋을 생성할 수 있다.
  • 컬럼의 값과 통계값을 비교해서 보거나 결측치 처리등에 사용할 수있다.
# 각각의 원소값과 통계량을 같이 볼 때
# 결측치 채울 때

# 트랜스폼 사용하기
df.groupby('fruits').transform(lambda x:10)

# 트랜스폼으로 평균
df.groupby('fruits').transform('mean')
# 그룹 별로 평균을 내서 묶어서 주는게 아니라, 각자 준다.
# 형태를 유지하면서 각각의 항목에 채워준다.

2.2 원본에 통계치 붙여서 비교하기


2.2.1 insert

  • 시리즈를 데이터 프레임의 중간 컬럼으로 삽입할 때 사용한다.
  • 구문
    • df.insert(삽입할 index : int, 컬럼 이름 : str, 삽입할 Series)
# 원본을 유지하기 위해 카피하기
df2 = df.copy()
df2.head()

# 사이에 넣어주기
# insert 중간 열에 끼워넣을 때 사용.
# 시리즈를 데이터 프레임의 중간 컬럼으로 삽입할 때 사용.

r = df.groupby('fruits').transform('mean')
r

# 인서트를 이용해 삽입해보기
df2.insert(2, '과일별 cnt1 평균', r['cnt1'])
# 반환하지 않는다. 원본이 변한다는 뜻

df2

# 컬럼 추가 생성
df2['과일별 cnt2 평균'] = r['cnt2']
# 이렇게 하면 맨 마지막에 추가된다.

df2.head() # 완성

3. pivot_table


3.1 pivot_table()


  • 개념 설명
    • 엑셀의 pivot table 기능을 제공하는 메소드.
    • 분류별 집계(Group으로 묶어 집계)를 처리하는 함수로 group으로 묶고자 하는 컬럼을 행과 열로 위치시키고 집계값을 값으로 보여준다.
    • 역할은 groupby() 를 이용한 집계와 같다.
  • 구문
DataFrame.pivot_table(
values=None,
index=None,
columns=None,
aggfunc='mean',
fill_value=None,
margins=False,
dropna=True,
margins_name='All')
  • 파라미터, 매개변수
    • index
      • 문자열 또는 리스트. index로 올 컬럼들 => groupby였으면 묶었을 컬럼
    • columns
      • 문자열 또는 리스트. column으로 올 컬럼들 => groupby였으면 묶었을 컬럼 (index/columns가 묶여서 groupby에 묶을 컬럼들이 된다.)
    • values
      • 문자열 또는 리스트. 집계할 대상 컬럼들
    • aggfunc
      • 집계함수 지정. 함수, 함수이름문자열, 함수리스트(함수이름 문자열/함수객체), dict: 집계할 함수
      • 기본(생략시): 평균을 구한다. (mean이 기본값)
    • fill_value, dropna
      • fill_value: 집계시 NA가 나올경우 채울 값
      • dropna: boolean. 컬럼의 전체값이 NA인 경우 그 컬럼 제거(기본: True)
    • margins/margins_name
      • margin: boolean(기본: False). 총집계결과를 만들지 여부.
      • margin_name: margin의 이름 문자열로 지정 (생략시 All)

3.2 한 개의 컬럼을 grouping 해서 집계


  • 항공사별 비행시간의 평균
  • 사용컬럼
    • grouping할 컬럼
      • AIRLINE: 항공사
    • 집계대상컬럼
      • AIR_TIME
  • 집계: mean
flights = pd.read_csv('data/flights.csv', encoding='UTF-8')
flights.shape

# 에어라인으로 그룹지은 에어타임의 평균
flights.groupby('AIRLINE')['AIR_TIME'].mean()

# 피봇 테이블
flights.pivot_table(values='AIR_TIME', index='AIRLINE', aggfunc='mean')
# 결과가 무적권 테이터 프레임으로 나온다.
# index 그룹핑할 대상을 인덱스에 지정해 준다.
# aggfunc
# 위나 아래나 똑같다. 차이가 있다면 데이터 프레임으로 만들어 준다는 것

# sql의 롤업같이 중간 집계
# flights.pivot_table(values='AIR_TIME', index='AIRLINE', aggfunc='mean', margins=True)
# margins all 전체 평균

# 이름 지정해 줄 수 있음
flights.pivot_table(values='AIR_TIME', index='AIRLINE', aggfunc='mean', margins=True, margins_name='전체평균')

# 그룹핑할 인덱스를 컬럼으로 지정하기
flights.pivot_table(values='AIR_TIME', columns='AIRLINE', aggfunc='mean')

# 굳이 피벗 테이블을 써야되나?
# 하나만 그룹핑해서 쓸 때는 굳이 쓸 필요없다.

3.3 두 개의 컬럼을 grouping 해서 집계


  • 항공사/출발공항코드 별 취소 총수 (1이 취소이므로 합계를 구한다.)
  • 사용컬럼
    • grouping할 컬럼
      • AIRLINE: 항공사
      • ORG_AIR: 출발 공항코드
    • 집계대상컬럼
      • CANCELLED: 취소여부 - 1:취소, 0: 취소안됨
  • 집계: sum
# 취소 건 수 구하기
flights.groupby(['AIRLINE', 'ORG_AIR'])['CANCELLED'].sum()

# 두 개로 그룹핑해서 집계할 때. 피벗 테이블
flights.pivot_table(values='CANCELLED', index='AIRLINE', columns='ORG_AIR', aggfunc='sum')
# 이거 구나. 왜 쓰는지 알겠다.
# NaN인 애들은 겹치는 게 없는 친구들

# 결측치에 특정한 값 넣어주기
flights.pivot_table(values='CANCELLED', index='AIRLINE', columns='ORG_AIR', aggfunc='sum', fill_value=-1)

# 중간 계 마진스
flights.pivot_table(values='CANCELLED', index='AIRLINE', columns='ORG_AIR', aggfunc='sum', margins=True)

3.4 세 개 이상의 컬럼을 grouping해서 2개 이상 집계


  • 항공사/월/출발공항코드 별 최대/최소 연착시간
  • grouping할 컬럼
    • AIRLINE:항공사
    • MONTH:월
    • ORG_AIR: 출발지 공항
  • 집계 대상컬럼
    • ARR_DELAY: 연착시간
  • 집계 : min, max
#
flights.groupby(['AIRLINE','MONTH','ORG_AIR'])['ARR_DELAY'].agg(['min','max'])

# 피봇 테이블
flights.pivot_table(values='ARR_DELAY', index=['AIRLINE','MONTH'], columns='ORG_AIR', aggfunc=['min','max'])

4. apply⭐


Series, DataFrame의 데이터 일괄 처리

4.1 apply()


  • 기본 개념
    • 데이터프레임의 행들과 열들 또는 Series의 원소들에 공통된 처리를 할 때 apply 함수를 이용하면 반복문을 사용하지 않고 일괄 처리가 가능하다.
  • 데이터 프레임
    • 기본 개념
      • 인수로 행이나 열을 받는 함수를 apply 메서드의 인수로 넣으면 데이터프레임의 행이나 열들을 하나씩 함수에 전달한다.
    • 구문
      DataFrame.apply(함수, axis=0, args=())
    • 매개변수, 파라미터
      • 함수: DataFrame의 행들 또는 열들을 전달할 함수
      • axis: 0-행을 전달, 1-열을 전달 (기본값 0) G: 0이 행이다...
      • args: 행/열 이외에 전달할 매개변수를 위치기반(순서대로) 튜플로 전달
  • 시리즈
    • 기본 개념
      • 인수로 Series의 원소들을 받는 함수를 apply 메소드의 인수로 넣으면 Series의 원소들을 하나씩 함수로 전달한다.
    • 구문
      • Series.apply(함수, args=())
    • 파라미터
      • 함수: Series의 원소들을 전달할 함수
      • args: 원소 이외에 전달할 매개변수를 위치기반(순서대로) 튜플로 전달
arr = np.arange(24).reshape(6,4)
df = pd.DataFrame(arr, columns=['NO1','NO2','NO3','NO4'])
df

# 함수 생성
def test(x):
    print(type(x))
    return x*10
    
# 시리즈에 어플라이 적용하기
df['NO1'].apply(test) # 테스트 함수를 일괄 적용해라! 라는 뜻
# 원본이 바뀌지는 않는다.
# 집계보다는 그냥 일괄적인 처리 느낌

# 마찬가지로 간단한 건 람다로 처리
df['NO1'].apply(lambda x:x*10)

# 데이터 프레임에 어플라이 사용하기
df.apply(test) # 기본적으로 axis=0 한 행씩 넘어간다.

df.apply(np.sum)

df.apply(np.sum, axis=1)

# 요런 것도 가능.
df['NO4'].apply(lambda x:'{}원'.format(x))

5. cut과 qcut


cut()/qcut() - 연속형(실수)을 범주형으로 변환

5.1 cut()


  • 기본 개념
    • cut() : 지정한 값을 기준으로 구간을 나눠 그룹으로 묶는다.
  • 구문
    • pd.cut(x, bins,right=True, labels=None)
  • 매개변수
    • x: 나눌 대상. 1차원 배열형태의 자료구조
    • bins: 나누는 기준값(구간경계)을 리스트로 전달
    • right: 구간경계의 오른쪽(True)을 포함할지 왼쪽(False)을 포함할지
    • labels: 각 구간의 label을 리스트로 전달

5.2 qcut()


  • 기본 개념
    • qcut() : 데이터를 오름차순으로 정렬한 뒤 데이터 개수가 같도록 지정한 개수만큼의 구간으로 나눈다.
  • 구문
    • pd.qcut(x, q, labels)
  • 매개변수
    • x: 나눌 대상. 1차원 배열형태의 자료구조
    • q: 나눌 개수
age = pd.Series(np.random.randint(80, size=30))
age

age.value_counts()

# cut으로 나누기
bins = [-1, 9, 21, 40, 80]
age_group = pd.cut(age, bins)
# () : 포함 안함
# [] : 포함한다.
age_group

df = pd.DataFrame({'나이':age, '나이대':age_group})
df

# 라벨 지정해주기
labels = ['유아','청소년','청년','중장년']
age_group = pd.cut(age, bins, labels=labels)
age_group

df = pd.DataFrame({'나이':age, '나이대':age_group})
df

# 응용해보기
df.groupby('나이대')['나이'].agg(['mean','count'])

# qcut
age_group2 = pd.qcut(age, q=5, labels=['유아','청소년','청년','중년','노년'])
age_group2

pd.DataFrame({'나이':age,'나이대':age_group2})
# 컷은 지정해서 자르지만 큐컷은 균등하게 알아서 나눠줌
# 그래서 범위를 알 수가 없다.

age_group2 = pd.qcut(age, q=5, labels=['유아','청소년','청년','중년','노년'], retbins=True)
type(age_group2)

age_group2[0]
age_group2[1]

pd.DataFrame({'나이':age,'나이대':age_group2[0]})
profile
대한민국 4차 산업의 역군을 꿈꾸며.

0개의 댓글