포스트

Aggregation_And_Grouping

Aggregation_And_Grouping

Aggregation_And_Grouping

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import numpy as np
import pandas as pd


class display(object):
  """Display HTML representation of multiple objects"""
  template = """<div style="float: left; padding: 10px;">
    <p style='font-family:"Courier New", Courier, monospace'>{0}</p>{1}
    </div>"""

  def __init__(self, *args):
    self.args = args

  def _repr_html_(self):
    return '\n'.join(self.template.format(a, eval(a)._repr_html_())
                     for a in self.args)

  def __repr__(self):
    return '\n\n'.join(a + '\n' + repr(eval(a))
                       for a in self.args)

Planets Data

1
2
3
4
5
# 이 데이터는 외행성 주변에서 발견한 행성에 대한 정보 제공
import seaborn as sns

planets = sns.load_dataset('planets')
planets.shape
1
(1035, 6)
1
planets.head()
methodnumberorbital_periodmassdistanceyear
0Radial Velocity1269.3007.1077.402006
1Radial Velocity1874.7742.2156.952008
2Radial Velocity1763.0002.6019.842011
3Radial Velocity1326.03019.40110.622007
4Radial Velocity1516.22010.50119.472009

Pandas의 간단한 집계 연산 Simple Aggregation in Pandas

1
2
3
4
# Series
rng = np.random.RandomState(42)
ser = pd.Series(rng.rand(5))
print("ser:\n", ser, "\n\nser.sum():", ser.sum(), "\n\nser.mean():", ser.mean())
1
2
3
4
5
6
7
8
9
10
11
ser:
 0    0.374540
1    0.950714
2    0.731994
3    0.598658
4    0.156019
dtype: float64 

ser.sum(): 2.811925491708157 

ser.mean(): 0.5623850983416314
1
2
3
4
# DataFrame
df = pd.DataFrame({'A': rng.rand(5),
                   'B': rng.rand(5)})
print("df:\n", df, "\n\ndf.mean():\n", df.mean(), "\n\ndf.mean(axis='columns'):\n", df.mean(axis='columns'))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
df:
           A         B
0  0.155995  0.020584
1  0.058084  0.969910
2  0.866176  0.832443
3  0.601115  0.212339
4  0.708073  0.181825 

df.mean():
 A    0.477888
B    0.443420
dtype: float64 

df.mean(axis='columns'):
 0    0.088290
1    0.513997
2    0.849309
3    0.406727
4    0.444949
dtype: float64
1
2
# describe() --> 각 열에 대한 여러 일반적인 집계를 계산하고 결과를 반환
planets.dropna().describe()
numberorbital_periodmassdistanceyear
count498.00000498.000000498.000000498.000000498.000000
mean1.73494835.7786712.50932052.0682132007.377510
std1.175721469.1282593.63627446.5960414.167284
min1.000001.3283000.0036001.3500001989.000000
25%1.0000038.2722500.21250024.4975002005.000000
50%1.00000357.0000001.24500039.9400002009.000000
75%2.00000999.6000002.86750059.3325002011.000000
max6.0000017337.50000025.000000354.0000002014.000000

Pandas의 집계 메서드 목록

AggregationDescription
count()항목 전체 개수 Total number of items
first(), last()첫 항목과 마지막 항목 First and last item
mean(), median()평균값과 중앙값 Mean and median
min(), max()최솟값과 최댓값 Minimum and maximum
std(), var()표준편차와 분산 Standard deviation and variance
mad()절대 평균 편차 Mean absolute deviation
prod()전체 항목의 곱 Product of all items
sum()전체 항목의 합 Sum of all items

GroupBy: Split, Apply, Combine 분할, 적용, 결합

  • 분할 단계: 지정된 키 값을 기준으로 DataFrame을 나누고 분류하는 단계
  • 적용 단계: 개별 그룹 내에서 일반적으로 집계, 변환, 필터링 같은 함수를 계산
  • 결합 단계: 이 연산의 결과를 결과 배열에 병합

png

1
2
3
df = pd.DataFrame({'key': ['A', 'B', 'C', 'A', 'B', 'C'],
                   'data': range(6)}, columns=['key', 'data'])
df
keydata
0A0
1B1
2C2
3A3
4B4
5C5
1
2
# 분할-적용-결합 연산 계산 --> DataFrameGroupBy 객체 리턴
df.groupby('key')
1
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001F4DCD07D70>
1
2
# DataFrameGroupBy 객체에 집계 연산 적용
display("df.groupby('key').sum()", "df.groupby('key').mean()", "df.groupby('key').max()")

df.groupby('key').sum()

keydata
A3
B5
C7

df.groupby('key').mean()

keydata
A1.5
B2.5
C3.5

df.groupby('key').max()

keydata
A3
B4
C5

The GroupBy object

Column indexing

GroupBy 객체는 DataFrame과 동일한 방식으로 열 인덱싱을 지원하며 수정된 GroupBy 객체를 리턴

1
planets.groupby('method')
1
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x000001F4DCD07800>
1
planets.groupby('method')['orbital_period']
1
<pandas.core.groupby.generic.SeriesGroupBy object at 0x000001F4DD0A0350>
1
planets.groupby('method')['orbital_period'].median()
1
2
3
4
5
6
7
8
9
10
11
12
method
Astrometry                         631.180000
Eclipse Timing Variations         4343.500000
Imaging                          27500.000000
Microlensing                      3300.000000
Orbital Brightness Modulation        0.342887
Pulsar Timing                       66.541900
Pulsation Timing Variations       1170.000000
Radial Velocity                    360.200000
Transit                              5.714932
Transit Timing Variations           57.011000
Name: orbital_period, dtype: float64

Iteration over groups

GroupBy 객체는 그룹을 직접 순회할 수 있도록 지원하며, 각 그룹을 Series나 DataFrame으로 리턴

1
2
for (method, group) in planets.groupby('method'):
  print("{0:30s} shape={1}".format(method, group.shape))
1
2
3
4
5
6
7
8
9
10
Astrometry                     shape=(2, 6)
Eclipse Timing Variations      shape=(9, 6)
Imaging                        shape=(38, 6)
Microlensing                   shape=(23, 6)
Orbital Brightness Modulation  shape=(3, 6)
Pulsar Timing                  shape=(5, 6)
Pulsation Timing Variations    shape=(1, 6)
Radial Velocity                shape=(553, 6)
Transit                        shape=(397, 6)
Transit Timing Variations      shape=(4, 6)

Dispatch methods

GroupBy 객체가 명시적으로 구현하지 않은 메서드는 객체에 상관없이 일부 파이썬 클래스 매직을 통해 그 그룹에 전달되고 호출
Dispatch methods는 각 개별 그룹에 적용되고 그 결과는 GroupBy 내에서 결합돼 리턴

1
planets.groupby('method')['year'].describe().unstack()
1
2
3
4
5
6
7
8
9
10
11
12
13
       method                       
count  Astrometry                          2.0
       Eclipse Timing Variations           9.0
       Imaging                            38.0
       Microlensing                       23.0
       Orbital Brightness Modulation       3.0
                                         ...  
max    Pulsar Timing                    2011.0
       Pulsation Timing Variations      2007.0
       Radial Velocity                  2014.0
       Transit                          2014.0
       Transit Timing Variations        2014.0
Length: 80, dtype: float64

집계, 필터, 변환, 적용 Aggregate, filter, transform, apply

1
2
3
4
5
6
rng = np.random.RandomState(0)
df = pd.DataFrame({'key': ['A', 'B', 'C', 'A', 'B', 'C'],
                   'data1': range(6),
                   'data2': rng.randint(0, 10, 6)},
                  columns=['key', 'data1', 'data2'])
df
keydata1data2
0A05
1B10
2C23
3A33
4B47
5C59

Aggregation

1
2
# 문자열, 함수, 리스트 등을 취해 한 번에 모든 집계를 계산
df.groupby('key').aggregate(['min', 'median', 'max'])
data1data2
minmedianmaxminmedianmax
key
A01.5334.05
B12.5403.57
C23.5536.09
1
2
# 열 이름을 해당 열에 적용될 연산에 매핑하는 딕셔너리 전달
df.groupby('key').aggregate({'data1': 'min', 'data2': 'max'})
data1data2
key
A05
B17
C29

Filtering

filter() 함수는 그룹이 필터링을 통과하는지 아닌지를 지정하는 부울 값을 리턴

1
2
3
4
5
6
# 그룹 속성을 기준으로 데이터를 걸러냄
def filter_func(x):
  return x['data2'].std() > 4


display('df', "df.groupby('key').std()", "df.groupby('key').filter(filter_func)")

df

keydata1data2
0A05
1B10
2C23
3A33
4B47
5C59

df.groupby('key').std()

data1data2
key
A2.121321.414214
B2.121324.949747
C2.121324.242641

df.groupby('key').filter(filter_func)

keydata1data2
1B10
2C23
4B47
5C59

Transformation

1
2
# 재결합을 위해 전체 데이터의 변환된 버전을 반환 --> 결과는 입력과 같은 형상
df.groupby('key').transform(lambda x: x - x.mean())
data1data2
0-1.51.0
1-1.5-3.5
2-1.5-3.0
31.5-1.0
41.53.5
51.53.0

The apply() method

임의의 함수를 그룹 결과에 적용할 때 사용
DataFrame을 취해 Pandas 객체나 스칼라를 반환
결합 연산은 반환된 출력값 유형에 따라 조정

1
2
3
4
5
6
7
8
# 첫 번째 열을 두 번째 열의 합계로 정규화
def norm_by_data2(x):
  # x is a DataFrame of group values
  x['data1'] /= x['data2'].sum()
  return x


display('df', "df.groupby('key').apply(norm_by_data2, include_groups=False)")

df

keydata1data2
0A05
1B10
2C23
3A33
4B47
5C59

df.groupby('key').apply(norm_by_data2, include_groups=False)

data1data2
key
A00.0000005
30.3750003
B10.1428570
40.5714297
C20.1666673
50.4166679

분할 키 지정 Specifying the split key

분할 키를 제공하는 리스트, 배열, 시리즈, 인덱스 A list, array, series, or index providing the grouping keys

1
2
L = [0, 1, 0, 1, 2, 0]
display('df', 'df.groupby(L).sum()', "df.groupby(df['key']).sum()")

df

keydata1data2
0A05
1B10
2C23
3A33
4B47
5C59

df.groupby(L).sum()

keydata1data2
0ACC717
1BA43
2B47

df.groupby(df['key']).sum()

data1data2
key
A38
B57
C712

인덱스를 그룹에 매핑한 딕셔너리나 시리즈 A dictionary or series mapping index to group

1
2
3
df2 = df.set_index('key')
mapping = {'A': 'vowel', 'B': 'consonant', 'C': 'consonant'}
display('df2', 'df2.groupby(mapping).sum()')

df2

data1data2
key
A05
B10
C23
A33
B47
C59

df2.groupby(mapping).sum()

data1data2
key
consonant1219
vowel38

Any Python function

1
display('df2', 'df2.groupby(str.lower).mean()')

df2

data1data2
key
A05
B10
C23
A33
B47
C59

df2.groupby(str.lower).mean()

data1data2
key
a1.54.0
b2.53.5
c3.56.0

A list of valid keys

1
df2.groupby([str.lower, mapping]).mean()
data1data2
keykey
avowel1.54.0
bconsonant2.53.5
cconsonant3.56.0

Grouping example

1
2
3
4
decade = 10 * (planets['year'] // 10)
decade = decade.astype(str) + 's'
decade.name = 'decade'
planets.groupby(['method', decade])['number'].sum().unstack().fillna(0)
decade1980s1990s2000s2010s
method
Astrometry0.00.00.02.0
Eclipse Timing Variations0.00.05.010.0
Imaging0.00.029.021.0
Microlensing0.00.012.015.0
Orbital Brightness Modulation0.00.00.05.0
Pulsar Timing0.09.01.01.0
Pulsation Timing Variations0.00.01.00.0
Radial Velocity1.052.0475.0424.0
Transit0.00.064.0712.0
Transit Timing Variations0.00.00.09.0
이 기사는 저작권자의 CC BY-NC 4.0 라이센스를 따릅니다.