지난번 포스팅에서는 Python pandas에서 Group By 집계 시에 grouped.agg()안에 칼럼과 함수를 매핑한 Dict를 사용하여 칼럼별로 특정 GroupBy 집계 함수를 적용하는 방법을 소개하였습니다. 


이번 포스팅에서는 Python pandas에서 Group By 집계 시에 grouped.apply()를 사용하여 여러개의 칼럼(Multiple Columns)에 대해서 각기 다른 함수들을 적용하는 방법을 소개하겠습니다. 지난번 포스팅과 비교를 해보시고, 편리하거나 이해하기 쉽다고 느껴지는 방법을 사용하면 되겠습니다. 


(1) 데이터프레임에서 여러개의 칼럼에 대해 다른 함수 적용하여 Group By 집계하기

    : grouped.apply(function)


(2) 계층적 인덱스를 가진 데이터프레임의 여러개의 칼럼에 대해 다른 함수 적용하여 Group By 집계하기

    : grouped(level=['index1', 'index2']).apply(function)






  (1) 데이터프레임에서 여러개의 칼럼에 대해 다른 함수 적용하여 Group By 집계하기

      : grouped.apply(function)



예제로 사용할 간단한 데이터프레임을 만들어보겠습니다. 



import numpy as np

import pandas as pd


df = pd.DataFrame({'grp_col_1' : ['a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b'], 

                   'grp_col_2' : ['c', 'c', 'd', 'd', 'd', 'e', 'e', 'f', 'f', 'f'], 

                   'val_1' : np.arange(10),                   

                   'val_2' : np.random.randn(10)})

 

df

grp_col_1grp_col_2val_1val_2
0ac00.829698
1ac1-0.766809
2ad2-2.119938
3ad30.885744
4ad4-1.135036
5be50.126890
6be62.755351
7bf70.441467
8bf8-1.166549
9bf9-0.712455





위에서 만든 데이터프레임의 'val_1' 칼럼에 대해서 평균(mean)과 표준편차(std)를 구하고, 'val_2' 칼럼에 대해서는 최대값(max)과 최소값(min), 그리고 범위(range)를 구하는 사용자 정의 함수 func()를 정의해보겠습니다. 처음에 빈 Dict 를 선언하고, 각 칼럼별 함수의 이름(key)과 함수를 적용한 결과(value)를 Dict의 key와 value로 매핑한 후에, 마지막에 pandas Series 로 반환하는 사용자 정의 함수입니다.



def func(x):

    d = {}

    d['val_1_mean'] = x['val_1'].mean()

    d['val_1_std'] = x['val_1'].std()

    d['val_2_max'] = x['val_2'].max()

    d['val_2_min'] = x['val_2'].min()

    d['val_2_range'] = x['val_2'].max() - x['val_2'].min()

    return pd.Series(d, index=['val_1_mean', 'val_1_std', 'val_2_max', 'val_2_min', 'val_2_range'])

 




위에서 정의한 사용자 정의 함수 func()를 Group By 집계 시 grouped.apply(func) 처럼 apply() 괄호 안에 함수이름을 써주면 됩니다. Group By 집계에 'grp_col_1', 'grp_col_2'의 두개 변수를 사용하였으므로 아래의 결과처럼 계층이 있는 인덱스(Hierarchical Index)를 가진 데이터프레임이 반환되었습니다. 



df_return = df.groupby(['grp_col_1', 'grp_col_2']).apply(func)

df_return


val_1_meanval_1_stdval_2_maxval_2_minval_2_range
grp_col_1grp_col_2
ac0.50.7071070.829698-0.7668091.596508
d3.01.0000000.885744-2.1199383.005682
be5.50.7071072.7553510.1268902.628461
f8.01.0000000.441467-1.1665491.608016

 




계층적 인덱스를 사용하고 싶지 않다면 reset_index() 로 인덱스를 칼럼으로 변환해주면 됩니다. 



df_return.reset_index()

grp_col_1grp_col_2val_1_meanval_1_stdval_2_maxval_2_minval_2_range
0ac0.50.7071070.829698-0.7668091.596508
1ad3.01.0000000.885744-2.1199383.005682
2be5.50.7071072.7553510.1268902.628461
3bf8.01.0000000.441467-1.1665491.608016

 




계층적 인덱스 전부 말고 일부만 선별해서 칼럼으로 변환을 하고 싶으면 reset_index(level='index_name') 처럼 reset_index() 의 안에 level 을 지정해주면 됩니다. 



df_return.reset_index(level='grp_col_2')

grp_col_2val_1_meanval_1_stdval_2_maxval_2_minval_2_range
grp_col_1
ac0.50.7071070.829698-0.7668091.596508
ad3.01.0000000.885744-2.1199383.005682
be5.50.7071072.7553510.1268902.628461
bf8.01.0000000.441467-1.1665491.608016

 




계층적 인덱스를 아예 삭제하고 싶으면 reset_index(drop=True) 처럼 drop=True 를 추가해주면 됩니다. (물론, 이렇게하면 Group By가 무엇을 기준으로 되었는지 파악이 불가능하기 때문에 사용하면 안될거 같긴 합니다. ^^;;;)



df_return.reset_index(drop=True)

val_1_meanval_1_stdval_2_maxval_2_minval_2_range
00.50.7071070.829698-0.7668091.596508
13.01.0000000.885744-2.1199383.005682
25.50.7071072.7553510.1268902.628461
38.01.0000000.441467-1.1665491.608016

 




Group By로 집계되어 반환된 객체가 데이터프레임으로 특정 칼럼만 선택할 수 있습니다. 예를 들어, 'val_1_mean', 'val_1_std'의 두 개 칼럼만 선택해보면 아래와 같습니다. 



df_return[['val_1_mean', 'val_1_std']]

val_1_meanval_1_std
grp_col_1grp_col_2
ac0.50.707107
d3.01.000000
be5.50.707107
f8.01.000000

 





  (2) 계층적 인덱스를 가진 데이터프레임의 여러개의 칼럼에 대해 다른 함수 적용하여 Group By 집계하기

      : grouped(level=['index1', 'index2']).apply(function)


위의 (1)번 예에서 들었던 데이터프레임과 'val_1', 'val_2' 의 숫자형 변수와 값은 동일하며, Group By 집계를 하는 기준이 되는 'grp_col_1', 'grp_col_2' 변수는 'grp_idx_1', 'grp_idx_2' 라는 이름의 인덱스 이름으로 하여 계층적 인덱스로 하여 데이터프레임을 만들어보겠습니다. 


pd.MultiIndex.from_arrays() 를 사용하여 계층적 인덱스를 만들어줍니다. (R이나 SQL을 사용하다가 Python 의 계층적 인덱스를 처음 보면 '이게 뭐지?' 싶었는데요, 자꾸 써보니 나름 편리합니다)


pd.DataFrame() 으로 데이터프레임을 만들 때 index 에  pd.MultiIndex.from_arrays() 로 만든 인덱스를 할당해주면 됩니다. 



# How to make a DataFrame with Hierarchical Index

arrays = [['a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b'], 

         ['c', 'c', 'd', 'd', 'd', 'e', 'e', 'f', 'f', 'f']]


myindex = pd.MultiIndex.from_arrays(arrays, names=('grp_idx_1', 'grp_idx_2'))

 


df2 = pd.DataFrame({'val_1': np.arange(10), 

                    'val_2': np.random.randn(10)}, 

                   index = myindex)


df2

val_1val_2
grp_idx_1grp_idx_2
ac0-0.491750
c10.507519
d20.099639
d30.669201
d40.714737
be5-0.865795
e6-1.174955
f70.878559
f8-0.877475
f9-0.323399

 




계층적 인덱스를 가진 데이터프레임에 대해 Group By 집계를 할 때는 groupby(level=['index_1', 'index_2']).apply(function) 의 형태로 지정을 해주면 됩니다. groupby() 로 집계 기준을 설정하고 apply(function)으로 함수를 지정해주는 것은 위의 (1)번과 같은데요, groupby()의 안에 level=['index_1', 'index_2'] 처럼 입력하는 부분이 다릅니다. 



df2.groupby(level=['grp_idx_1', 'grp_idx_2']).apply(func)

val_1_meanval_1_stdval_2_maxval_2_minval_2_range
grp_idx_1grp_idx_2
ac0.50.7071070.507519-0.4917500.999269
d3.01.0000000.7147370.0996390.615099
be5.50.707107-0.865795-1.1749550.309161
f8.01.0000000.878559-0.8774751.756035

 



많은 도움이 되었기를 바랍니다. 

Posted by R Friend R_Friend

지난번 포스팅에서는 Python pandas의 GroupBy 집계 메소드와 함수에 대해서 알아보았습니다. 


이번 포스팅에서는 Python pandas의 GroupBy 집계를 할 때 grouped.agg() 를 사용하여 다수의 함수를 적용하는 몇 가지 방법을 소개하고자 합니다. 


(1) 함수 리스트(List)를 사용하여 다수의 GroupBy 집계 함수를 동일한 칼럼에 적용하기

(2) 칼럼과 함수를 매핑한 Dict를 사용하여 칼럼별로 특정 GroupBy 집계 함수를 적용하기

(3) (이름, 함수)의 튜플 (Tuples of (name, function))을 사용하여 GroupBy 집계 함수에 이름 부여하기



[ Python pandas: GroupBy with multiple functions using lists, Dicts, tuples ]



예제로 사용할 데이터는 UCI Machine Learning Repository에 있는 Abalone data set 입니다. 전복의 둘레, 두께, 높이, 전체 무게, 껍질 무게 등 4,177개의 전복을 측정해 놓은 데이터셋입니다. 



[ UCI Machine Learning Repository ]

Name Data Type Meas. Description ---- --------- ----- ----------- Sex nominal M, F, and I (infant) Length continuous mm Longest shell measurement Diameter continuous mm perpendicular to length Height continuous mm with meat in shell Whole weight continuous grams whole abalone Shucked weight continuous grams weight of meat Viscera weight continuous grams gut weight (after bleeding) Shell weight continuous grams after being dried Rings integer +1.5 gives the age in years



UCI machine learning repository 웹사이트로부터 Abalone 데이터셋을 csv파일을 다운로드 받아서 pandas DataFrame로 불러오도록 하겠습니다. 



# Importing common libraries

import numpy as np

import pandas as pd

 

# Import Abalone data set from UCI machine learning repository directly

import csv

import urllib2

url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/abalone/abalone.data'

downloaded_data  = urllib2.urlopen(url)

abalone = pd.read_csv(downloaded_data, 

                      names = ['sex', 'length', 'diameter', 'height', 

                               'whole_weight', 'shucked_weight', 'viscera_weight', 

                               'shell_weight', 'rings'], 

                      header = None)


abalone.head()

sexlengthdiameterheightwhole_weightshucked_weightviscera_weightshell_weightrings
0M0.4550.3650.0950.51400.22450.10100.15015
1M0.3500.2650.0900.22550.09950.04850.0707
2F0.5300.4200.1350.67700.25650.14150.2109
3M0.4400.3650.1250.51600.21550.11400.15510
4I0.3300.2550.0800.20500.08950.03950.0557




예제에서 GroupBy 집계 시 그룹을 나누는 기준으로 사용할 용도로 'length' 변수에 대해 중앙값을 기준으로 큰지, 작은지 여부에 따라 'length_cat' 라는 범주형 변수를 하나 더 만들어보겠습니다. 



abalone['length_cat'] = np.where(abalone.length > np.median(abalone.length), 

                                 'length_long', # True

                                 'length_short') # False


abalone[['length', 'length_cat']][:10]

lengthlength_cat
00.455length_short
10.350length_short
20.530length_short
30.440length_short
40.330length_short
50.425length_short
60.530length_short
70.545length_short
80.475length_short
90.550length_long

 





 (1) 함수 리스트(List)를 사용하여 다수의 GroupBy 집계 함수를 동일한 칼럼에 적용하기


'sex' ('F', 'I', 'M' 계급), 'length_cat' ('length_short', 'length_long' 계급) 의 두 개의 범주형 변수를 사용하여 GroupBy 집계 시 그룹을 나누는 기준으로 사용하겠으며, 'whole_weight' 연속형 변수에 대해 GroupBy 집계 함수를 적용하여 그룹 집계를 해보겠습니다.  



grouped_ww = abalone.groupby(['sex', 'length_cat'])['whole_weight']

grouped_ww

<pandas.core.groupby.SeriesGroupBy object at 0x10a7e0290> 





먼저, 복습을 하는 차원에서 지난번 포스팅에서 소개했던 '단일 함수'를 사용하여 GroupBy 집계하는 두가지 방법, 즉 (1) GroupBy method를 사용하거나 아니면 (2) grouped.agg(함수)를 사용하는 방법을 소개하면 아래와 같습니다. 하나의 집계함수를 적용하면 반환되는 결과는 Series 가 됩니다. 


(방법1) GroupBy methods

(방법2) grouped.agg(function)

 

grouped_ww.mean() # Series

sex  length_cat  
F    length_long     1.261330
     length_short    0.589702
I    length_long     0.923215
     length_short    0.351234
M    length_long     1.255182
     length_short    0.538157
Name: whole_weight, dtype: float64

 

grouped_ww.agg('mean') # Series

sex  length_cat  
F    length_long     1.261330
     length_short    0.589702
I    length_long     0.923215
     length_short    0.351234
M    length_long     1.255182
     length_short    0.538157
Name: whole_weight, dtype: float64




이제부터 '여러개의 함수'를 적용하여 GroupBy 집계하는 방법을 소개하겠습니다. 먼저, GroupBy 집계하려는 함수들의 문자열 리스트(list)로 grouped.agg() 에 적용하는 방법입니다.  이처럼 여러개의 집계함수를 적용하면 반환되는 결과는 DataFrame이 됩니다. 



grouped_ww.agg(['size', 'mean', 'std', 'min', 'max']) # DataFrame

sizemeanstdminmax
sexlength_cat
Flength_long8891.2613300.3296560.64052.6570
length_short4180.5897020.2024000.08001.3580
Ilength_long1880.9232150.2183340.55852.0495
length_short11540.3512340.2042370.00201.0835
Mlength_long9661.2551820.3546820.59902.8255
length_short5620.5381570.2464980.01551.2825




function_list = ['size', 'mean', 'std', 'min', 'max']

grouped_ww.agg(function_list)

sizemeanstdminmax
sexlength_cat
Flength_long8891.2613300.3296560.64052.6570
length_short4180.5897020.2024000.08001.3580
Ilength_long1880.9232150.2183340.55852.0495
length_short11540.3512340.2042370.00201.0835
Mlength_long9661.2551820.3546820.59902.8255
length_short5620.5381570.2464980.01551.2825

 




물론, "다수의 칼럼"에 대해서 여러개의 함수를 적용하는 것도 가능합니다. 아래의 예에서는 'whole_weight', 'shell_weight'의 두 개의 칼럼에 대해서 GroupBy 집계 함수 리스트(list)를 적용하여 집계하여 보았습니다. 



grouped = abalone.groupby(['sex', 'length_cat'])

function_list = ['size', 'mean', 'std']

groupby_result = grouped['whole_weight', 'shell_weight'].agg(function_list)

groupby_result

whole_weightshell_weight
sizemeanstdsizemeanstd
sexlength_cat
Flength_long8891.2613300.3296568890.3600130.104014
length_short4180.5897020.2024004180.1786500.063085
Ilength_long1880.9232150.2183341880.2732470.064607
length_short11540.3512340.20423711540.1045490.061003
Mlength_long9661.2551820.3546829660.3516830.102636
length_short5620.5381570.2464985620.1621410.075629




GroupBy 집계 결과가 pandas DataFrame으로 반환된다고 하였으므로, DataFrame에서 사용하는 Indexing 기법을 그대로 사용할 수 있습니다. 예를 들어, 칼럼을 기준으로 집계 결과 데이터프레임인 groupby_result 로 부터 'shell_weight' 변수에 대한 결과만 Indexing 해보겠습니다. 



groupby_result['shell_weight']

sizemeanstd
sexlength_cat
Flength_long8890.3600130.104014
length_short4180.1786500.063085
Ilength_long1880.2732470.064607
length_short11540.1045490.061003
Mlength_long9660.3516830.102636
length_short5620.1621410.075629

 


groupby_result['shell_weight'][['size', 'mean']]

sizemean
sexlength_cat
Flength_long8890.360013
length_short4180.178650
Ilength_long1880.273247
length_short11540.104549
Mlength_long9660.351683
length_short5620.162141





GroupBy 집계 결과 데이터프레임으로부터 row를 기준으로 Indexing을 할 수도 있습니다. DataFrame에서 row 기준으로 indexing 할 때 DataFrame.loc[] 를 사용하는 것과 동일합니다. 



groupby_result.loc['M']

whole_weightshell_weight
sizemeanstdsizemeanstd
length_cat
length_long9661.2551820.3546829660.3516830.102636
length_short5620.5381570.2464985620.1621410.075629

 


groupby_result.loc['M', 'shell_weight']

sizemeanstd
length_cat
length_long9660.3516830.102636
length_short5620.1621410.075629






 (2) 칼럼과 함수를 매핑한 Dict를 사용하여 칼럼별로 특정 GroupBy 집계 함수를 적용하기 


먼저, 범위(range)와 IQR(Inter-Quartile Range)를 구하는 사용자 정의 함수를 정의한 후에 grouped.agg() 에 적용해보겠습니다.  



def range_func(x):

    max_val = np.max(x)

    min_val = np.min(x)

    range_val = max_val - min_val

    return range_val


def iqr_func(x):

    q3, q1 = np.percentile(x, [75, 25])

    iqr = q3 - q1

    return iqr

 




이제 Dicts를 사용하여 'whole_weight' 칼럼에는 size(), mean(), std() 메소드를 매핑하여 GroupBy 집계에 적용하고, 'shell_weight' 칼럼에는 range_func, iqr_func 사용자 정의 함수를 매핑하여 GroupBy 집계에 적용해보겠습니다. 


size(), mean(), std() 등의 메소드는 문자열(string)로 grouped.agg() 안에 넣어주어야 해서 작은따옴표('method_name')로 감싸주었으며, 사용자 정의 함수(UDF)는 작은따옴표 없이 그냥 써주면 됩니다. 



grouped.agg({'whole_weight': ['size', 'mean', 'std'], # put method's name as a string

            'shell_weight': [range_func, iqr_func]}) # UDF name

whole_weightshell_weight
sizemeanstdrange_funciqr_func
sexlength_cat
Flength_long8891.2613300.3296560.8500.127000
length_short4180.5897020.2024000.3780.080500
Ilength_long1880.9232150.2183340.4850.067875
length_short11540.3512340.2042370.3490.092750
Mlength_long9661.2551820.3546820.7760.124000
length_short5620.5381570.2464980.3750.102750

 





 (3) (이름, 함수)의 튜플 (Tuples of (name, function))을 사용하여 GroupBy 집계 함수에 이름 부여하기


위의 (2)번에서 Dicts를 사용하여 shell_weight 변수에 대해 range_func, iqr_func 사용자 정의 함수를 적용하여 GroupBy 집계를 하였는데요, 집계 결과로 반환된 데이터프레임의 변수 이름이 그대로 'range_func', 'iqr_func' 여서 왠지 좀 마음에 들지 않군요.  이럴 때 (이름, 함수) 의 튜플 (Tuples of (name, function))을 사용하여 함수에 특정 이름을 부여할 수 있습니다. 


아래 예제에서는 알아보기에 쉽도록 'range_func'는 'Range'라는 이름으로, 'iqr_func'는 'Inter-Quartile_Range'라는 이름을 부여하여 변경을 해보겠습니다. 



# (name, function) tuples

grouped.agg({'whole_weight': ['size', 'mean', 'std'], 

            'shell_weight': [('Range', range_func),  # (name, function) tuple

                                    ('Inter-Quartile_Range', iqr_func)]}) # (name, function) tuple

whole_weightshell_weight
sizemeanstdRange

Inter-Quartile_Range

sexlength_cat
Flength_long8891.2613300.3296560.8500.127000
length_short4180.5897020.2024000.3780.080500
Ilength_long1880.9232150.2183340.4850.067875
length_short11540.3512340.2042370.3490.092750
Mlength_long9661.2551820.3546820.7760.124000
length_short5620.5381570.2464980.3750.102750



많은 도움이 되었기를 바랍니다. 

Posted by R Friend R_Friend

지난번 포스팅에서는 row나 column 기준으로 GroupBy의 Group을 지정할 수 있는 4가지 방법으로 Dicts, Series, Functions, Index Levels 를 소개하였습니다. 


이번 포스팅에서는 Python pandas에서 연속형 변수의 기술통계량 집계를 할 수 있는 GroupBy 집계 메소드와 함수 (GroupBy aggregation methods and functions)에 대해서 소개하겠습니다. 


(1) GroupBy 메소드를 이용한 집계 (GroupBy aggregation using methods): (ex) grouped.sum()

(2) 함수를 이용한 GroupBy 집계 (GroupBy aggregation using functions): grouped.agg(function)



[ Python pandas Group By 집계 메소드와 함수 ]



pandas에서 GroupBy 집계를 할 때 (1) pandas에 내장되어 있는 기술 통계량 메소드를 사용하는 방법과, (2) (사용자 정의) 함수를 grouped.agg(function) 형태로 사용하는 방법이 있습니다. GroupBy 메소드는 성능이 최적화되어 있어 성능면에서 함수를 사용하는 것보다 빠르므로, 메소드가 지원하는 집단별 기술통계량 분석 시에는 메소드를 이용하는게 좋겠습니다. 


NA 값은 모두 무시되고 non-NA 값들에 대해서만 GroupBy method가 적용됩니다. 


기술 통계량들이 어려운게 하나도 없으므로 이번 포스팅은 좀 쉬어가는 코너로 가볍게 소개합니다. 설명에 사용한 간단한 예제 데이터프레임과 'group'변수를 대상으로 GroupBy object를 만들어보겠습니다. 



# Importing common libraries

import numpy as np

import pandas as pd


# sample DataFrame

df = pd.DataFrame({'group': ['a', 'a', 'a', 'b', 'b', 'b'], 

                  'value_1': np.arange(6), 

                 'value_2': np.random.randn(6)})

df

groupvalue_1value_2
0a0-1.739302
1a10.851955
2a20.874874
3b3-0.461543
4b40.880763
5b5-0.346675




# Making GroupBy object

grouped = df.groupby('group')

grouped

<pandas.core.groupby.DataFrameGroupBy object at 0x11136f550>




  (1) GroupBy 메소드를 이용한 집계 (GroupBy aggregation using methods)


(1-1) count(), sum()

count(): 그룹 내 non-NA 개수 

sum(): 그룹 내 non-NA 합 

 

grouped.count()

value_1value_2
group
a33
b33


grouped.sum() # DataFrame

value_1value_2
group
a3-0.012473
b120.072545


*cf. grouped.size() 도 grouped.count()와 동일한 결과를 반환함



위의 예에서 보면 'value_1', 'value_2' 변수가 숫자형이므로 pandas가 알아서 잘 찾아서 count()와 sum()을 해주었으며, 반환된 결과는 데이터프레임입니다. 



만약 특정 변수에 대해서만 그룹별 요약/집계를 하고 싶다면 해당 변수를 indexing해주면 되며, 한개 변수에 대해서만 GroupBy 집계를 하면 반환되는 결과는 Series가 됩니다. 한개 변수에 대해 GroupBy 집계해서 나온 Series를 데이터프레임으로 만들고 싶으면 pd.DataFrame() 를 사용해서 집계 결과를 데이터프레임으로 변환해주면 됩니다. 



grouped.sum()['value_2'] # Series

group

a   -0.012473
b    0.072545 

Name: value_2, dtype: float64



pd.DataFrame(grouped.sum()['value_2']) # DataFrame 

value_2
group
a-0.012473
b0.072545





(1-2) 최소값, 최대값: min(), max()

min(): 그룹 내 non-NA 값 중 최소값 

max(): 그룹 내 non-NA 값 중 최대값 

 

grouped.min()

value_1value_2
group
a0-1.739302
b3-0.461543



grouped.max()

value_1value_2
group
a20.874874
b50.880763





(1-3) 중심 경향: mean(), median()

mean(): 그룹 내 non-NA 값들의 평균값 

median(): 그룹 내 non-NA 값들의 중앙값 

 

grouped.mean()

value_1value_2
group
a1-0.004158
b40.024182



grouped.median()

value_1value_2
group
a10.851955
b4-0.346675





(1-4) 퍼짐 정도: std(), var(), quantile()


표준편차, 분산 계산에 n-1 자유도를 사용했으므로 샘플표준편차, 샘플분산으로 봐야겠네요. 

quantile() 의 괄호 안에 0~1 사이의 값을 넣어주면 분위수를 계산해주며, 최소값과 최대값을 등분하여 그 사이를 interpolation 하여 분위수를 계산하는 방식입니다. 


std(): 그룹 내 표준편차

var(): 그룹 내 분산

quantile(): 그룹 내 분위수 


grouped.std() 

value_1value_2
group
a1.01.502723
b1.00.744042



grouped.var()

value_1value_2
group
a12.258176
b10.553598

 

 # interpolation

grouped.quantile(0.1) 

0.1value_1value_2
group
a0.2-1.221051
b3.2-0.438569




(1-5) first(), last()

first(): 그룹 내 non-NA 값 중 첫번째 값 

last(): 그룹 내 non-NA 값 중 마지막 값 

 

grouped.first()

value_1value_2
group
a0-1.739302
b3-0.461543


 

grouped.last()

value_1value_2
group
a20.874874
b5-0.346675





(1-6) describe()

describe(): 그룹 별 기술통계량 

- 옆으로 길게

 describe().T: 그룹 별 기술통계량 

- 세로로 길게

 

grouped.describe()['value_1']

countmeanstdmin25%50%75%max
group
a3.01.01.00.00.51.01.52.0
b3.04.01.03.03.54.04.55.0


 

grouped.describe()['value_1'].T

groupab
count3.03.0
mean1.04.0
std1.01.0
min0.03.0
25%0.53.5
50%1.04.0
75%1.54.5
max2.05.0





  (2) 함수를 이용한 GroupBy 집계: grouped.agg(function)


필요로 하는 집계함수가 pandas GroupBy methods에 없는 경우 사용자 정의 함수를 정의해서 집계에 사용할 수 있습니다. IQR(Inter-Quartile Range, Q3 - Q1) 를 사용자 정의 함수로 정의하고, 이를 grouped.aggregate() 혹은 grouped.agg() 의 괄호 안에 넣어서 그룹 별로 IQR를 계산해보겠습니다. 



def iqr_func(x):

    q3, q1 = np.percentile(x, [75, 25])

    iqr = q3 - q1

    return iqr




grouped.aggregate(function) 

grouped.agg(function) 

 

grouped.aggregate(iqr_func)

value_1value_2
group
a11.307088
b10.671153


 

grouped.agg(iqr_func)

value_1value_2
group
a11.307088
b10.671153



위에서 사용자 정의함수로 정의해서 그룹별로 집계한 결과가 맞게 나온건지 quantile() 메소드로 그룹별 Q3 와 Q1을 계산해서 확인해보니, 위의 grouped.agg(iqr_func)가 잘 계산한거 맞네요. 



grouped.quantile([0.75, 0.25])

value_1value_2
group
a0.751.50.863414
0.250.5-0.443674
b0.754.50.267044
0.253.5-0.404109

 


다음번 포스팅에서는 grouped.agg() 의 좀더 다양한 사용법을 소개하겠습니다. 


많은 도움이 되었기를 바랍니다. 

Posted by R Friend R_Friend

이번 포스팅에서 Python pandas의 GroupBy 집계 방법 4가지를 소개하겠습니다. 


(1) Dicts를 사용한 GroupBy 집계

(2) Series를 사용한 GroupBy 집계

(3) Functions를 사용한 GroupBy 집계

(4) Index Levels를 사용한 GroupBy 집계


기본은 axis = 0으로서 row-wise 집계를 하게 되며, axis = 1 을 설정해주면 column-wise  집계를 하게 됩니다. 



[ pandas의 4가지 GroupBy 집계 방법 ]


  (1) Dicts를 이용한 GroupBy 집계


예제로 사용할 간단한 데이터프레임을 만들어보겠습니다. 



# importing libraries

 import numpy as np

 import pandas as pd

 from pandas import DataFrame

 from pandas import Series

 

# making sample dataset

 df = DataFrame(data=np.arange(20).reshape(4, 5),

               columns = ['c1', 'c2', 'c3', 'c4', 'c5'], 

               index = ['r1', 'r2', 'r3', 'r4'])


 df

c1c2c3c4c5
r101234
r256789
r31011121314
r41516171819





다음으로, 행 기준(row-wise), 열 기준(column-wise)으로 나누어서 Dicts를 사용해 GroupBy 집계하는 예를 들어보겠습니다. 



(1-1) 행 기준 Dicts를 이용한 GroupBy 집계 (row-wise GroupBy aggregation using Dicts, axis = 0) 



 mapping_dict_row = {'r1': 'row_g1', 

                   'r2': 'row_g1', 

                   'r3': 'row_g2', 

                   'r4': 'row_g2'}

 

 grouped_by_row = df.groupby(mapping_dict_row)


 grouped_by_row.sum()

c1c2c3c4c5
row_g15791113
row_g22527293133





(1-2) 열 기준 Dicts를 이용한 GroupBy 집계 (Column-wise GroupBy aggregation using Dicts, axis = 1)



 mapping_dict_col = {'c1': 'col_g1', 

                   'c2': 'col_g1', 

                   'c3': 'col_g2', 

                   'c4': 'col_g2', 

                   'c5': 'col_g2'}


 grouped_by_col = df.groupby(mapping_dict_col, axis=1)


 grouped_by_col.sum()

col_g1col_g2
r119
r21124
r32139
r43154





Series, Lists 로도 Dicts와 유사하게 GroupBy 집계를 할 수 있습니다. 


  (2) Series를 이용한 GroupBy 집계


(2-1) 행 기준 Series를 이용한 GroupBy 집계 (row-wise GroupBy aggregation using Series, axis = 0)



 mapping_series_row = Series(mapping_dict_row)


 mapping_series_row

r1    row_g1
r2    row_g1
r3    row_g2
r4    row_g2
dtype: object



 df.groupby(mapping_series_row).sum()

c1c2c3c4c5
row_g15791113
row_g22527293133





(2-2) 열 기준 Series를 이용한 GroupBy 집계 (column-wise GroupBy aggregation using Series, axis = 1)



 mapping_series_col = Series(mapping_dict_col)


 mapping_series_col

c1 col_g1

c2    col_g1
c3    col_g2
c4    col_g2
c5    col_g2 

dtype: object



 df.groupby(mapping_series_col, axis=1).sum()

col_g1col_g2
r119
r21124
r32139
r43154



 df.groupby(mapping_series_colaxis=1).mean()

col_g1col_g2
r10.53.0
r25.58.0
r310.513.0
r415.5

18.0





(2-3) 열 기준 Lists를 이용한 GroupBy 집계 (column-wise GroupBy aggregation using Lists, axis = 1)


Lists를 이용해서도 (2-2)와 동일한 집계 결과를 얻을 수 있습니다. 



 mapping_list_col = ['col_g1', 'col_g1', 'col_g2', 'col_g2', 'col_g2'] # lists


 df.groupby(mapping_list_col, axis=1).mean()

col_g1col_g2
r10.53.0
r25.58.0
r310.513.0
r415.518.0

 




Dicts와는 달리 Series나 List의 경우 Group으로 묶어 주려는 행이나 열의 인덱스 개수가 데이터프레임의 인덱스 개수와 일치해야 합니다. 만약 매핑하려는 Series나 Lists의 안의 원소 개수와 데이터프레임의 인덱스 개수가 다를 경우 'KeyError' 가 발생합니다. 


아래 예는 칼럼을 매핑하려는 mapping_list_col_2 리스트에 원소 개수가 6개인 반면에, df 데이터프레임에는 칼럼이 5개 밖에 없으므로 KeyError 가 발생하였습니다. 



 mapping_list_col_2 = ['col_g1', 'col_g1', 'col_g2', 'col_g2', 'col_g2', 'col_g2']


 df.groupby(mapping_list_col_2, axis=1).mean()

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-31-76bb72a2996c> in <module>()
----> 1 df.groupby(mapping_list_col_2, axis=1).mean()

/Users/ihongdon/anaconda3/envs/py2.7_tf1.4/lib/python2.7/site-packages/pandas/core/generic.pyc in groupby(self, by, axis, level, as_index, sort, group_keys, squeeze, **kwargs)
   4414         return groupby(self, by=by, axis=axis, level=level, as_index=as_index,
   4415                        sort=sort, group_keys=group_keys, squeeze=squeeze,
-> 4416                        **kwargs)
   4417 
   4418     def asfreq(self, freq, method=None, how=None, normalize=False,

/Users/ihongdon/anaconda3/envs/py2.7_tf1.4/lib/python2.7/site-packages/pandas/core/groupby.pyc in groupby(obj, by, **kwds)
   1697         raise TypeError('invalid type: %s' % type(obj))
   1698 
-> 1699     return klass(obj, by, **kwds)
   1700 
   1701 

/Users/ihongdon/anaconda3/envs/py2.7_tf1.4/lib/python2.7/site-packages/pandas/core/groupby.pyc in __init__(self, obj, keys, axis, level, grouper, exclusions, selection, as_index, sort, group_keys, squeeze, **kwargs)
    390                                                     level=level,
    391                                                     sort=sort,
--> 392                                                     mutated=self.mutated)
    393 
    394         self.obj = obj

/Users/ihongdon/anaconda3/envs/py2.7_tf1.4/lib/python2.7/site-packages/pandas/core/groupby.pyc in _get_grouper(obj, key, axis, level, sort, mutated)
   2688                 in_axis, name, level, gpr = False, None, gpr, None
   2689             else:
-> 2690                 raise KeyError(gpr)
   2691         elif isinstance(gpr, Grouper) and gpr.key is not None:
   2692             # Add key to exclusions

KeyError: 'col_g1'

 




  (3) Functions를 이용한 GroupBy 집계


재미있게도 GroupBy operator 에 함수를 사용할 수도 있습니다. 아래 예에서는 row_grp_func() 라는 사용자 정의 함수를 만들어서 GroupBy 합계 집계를 해보았습니다. 



 df

c1c2c3c4c5
r101234
r256789
r31011121314
r41516171819


 def row_grp_func(x):

    if x == 'r1' or x == 'r2':

        row_group = 'row_g1'

    else:

        row_group = 'row_g2'

    return row_group

 


 df.groupby(row_grp_func).sum()

c1c2c3c4c5
row_g15791113
row_g22527293133





  (4) Index Levels를 이용한 GroupBy 집계


마지막으로, 계층적 인덱스(Hierarchical index)를 가진 데이터프레임에 대해서 Index Levels를 사용하여 집계하는 방법을 소개하겠습니다. Level에 대해서 names 로 이름을 부여하여 사용하면 편리합니다. 계층적 인덱스는 R에는 없는 기능인데요, 자꾸 쓰다 보니 나름 유용합니다. 



 hier_columns = pd.MultiIndex.from_arrays([['col_g1', 'col_g1', 'col_g2', 'col_g2', 'col_g2'], 

                                         ['c1', 'c2', 'c3', 'c4', 'c5']], 

                                        names = ['col_level_1', 'col_level_2'])


 hier_columns

MultiIndex(levels=[[u'col_g1', u'col_g2'], [u'c1', u'c2', u'c3', u'c4', u'c5']],
           labels=[[0, 0, 1, 1, 1], [0, 1, 2, 3, 4]],
           names=[u'col_level_1', u'col_level_2'])



 hier_df = DataFrame(data = np.arange(20).reshape(4,5)

                   columns = hier_columns, 

                   index = ['r1', 'r2', 'r3', 'r4'])


 hier_df

col_level_1col_g1col_g2
col_level_2c1c2c3c4c5
r101234
r256789
r31011121314
r41516171819

 


 hier_df.groupby(level = 'col_level_1', axis=1).mean()

col_level_1col_g1col_g2
r10.53.0
r25.58.0
r310.513.0
r415.518.0




많은 도움이 되었기를 바랍니다. 

Posted by R Friend R_Friend

이번 포스팅에서는 Python pandas의 DataFrame에서 문자열 변수들을 가지고 일부 포맷 변형을 한 후에 새로운 변수를 만드는 방법을 소개하겠습니다. 이게 얼핏 생각하면 쉬울 것 같은데요, 또 한번도 본적이 없으면 어렵습니다. ^^; lambda, apply() 함수와 문자열 처리 메소드 등에 대해서 알고 있으면 이해가 쉽습니다. 



(1) 'id' 변수가 전체 5개 자리가 되도록 왼쪽에 비어있는 부분에 '0'을 채워서 새로운 변수 'id_2' 만들기

    (Left padding with zeros so that make 5 positions)


(2) 새로 만든 'id_2' 변수와 'name' 변수를 각 원소별로 합쳐서 데이터프레임 안에 새로운 변수 'id_name' 만들기

    (element-wise string concatenation with multiple inputs array in pandas DataFrame)






먼저, 예제로 사용할 간단한 DataFrame을 만들어보겠습니다. 


 

In [1]: import pandas as pd


In [2]: df = pd.DataFrame({'id': [1, 2, 10, 20, 100, 200], 

   ...:                    'name': ['aaa', 'bbb', 'ccc', 'ddd', 'eee', 'fff']})


In [3]: df

Out[3]: 

    id name

0    1  aaa

1    2  bbb

2   10  ccc

3   20  ddd

4  100  eee

5  200  fff





  (1) 'id' 변수가 전체 5개 자리가 되도록 왼쪽에 비어있는 부분에 '0'을 채워서 새로운 변수 'id_2' 만들기

     (Left padding with zeros so that make 5 positions)


lambda 로 format() 함수를 만들어서 apply() 로 적용을 하여 5자리 중에서 빈 자리를 '0'으로 채웠습니다.



In [4]: df['id_2'] = df['id'].apply(lambda x: "{:0>5d}".format(x))


In [5]: df

Out[5]: 

    id      name   id_2

0      1   aaa      00001

1      2   bbb     00002

2    10   ccc     00010

3    20  ddd    00020

4  100  eee     00100

5  200  fff      00200



다양한 숫자 포맷(number format) 함수는 https://mkaz.blog/code/python-string-format-cookbook/ 를 참고하세요. 




 (2) 새로 만든 'id_2' 변수와 'name' 변수를 각 원소별로 합쳐서 데이터프레임 안에

새로운 변수 'id_name' 만들기

    (element-wise string concatenation with multiple inputs array in pandas DataFrame)


그리고 역시 lambda 로 '_'를 중간 구분자로 해서 두 변수의 문자열을 결합('_'.join)하는 함수를 정의한 후에 apply() 로 적용하였습니다, 'axis = 1'을 설정해준 점 주의하시기 바랍니다. 


 

In [6]: df['id_name'] = df[['id_2', 'name']].apply(lambda x: '_'.join(x), axis=1)


In [7]: df

Out[7]: 

       id    name   id_2         id_name

0      1    aaa      00001    00001_aaa

1      2    bbb     00002    00002_bbb

2    10    ccc     00010     00010_ccc

3    20   ddd    00020    00020_ddd

4  100   eee    00100     00100_eee

5  200   fff     00200     00200_fff 





여기서 끝내면 좀 허전하고 아쉬우니 몇 가지 데이터 포맷 변경을 더 해보겠습니다.



(3) 'id' 변수의 값을 소숫점 두번째 자리까지 나타내는 새로운 변수 'id_3' 만들기


(4) 'name' 변수의 문자열을 전부 대문자로 바꾼 새로운 변수 'name_3' 만들기


(5) 데이터프레임 안의 'id_3'와 'name_3' 변수를 합쳐서 새로운 변수 'id_name_3' 만들기



(3) 'id' 변수의 값을 소숫점 두번째 자리까지 나타내는 새로운 변수 'id_3' 만들기


"{:.2f}".format() 함수를 사용하여 소숫점 두번째 자리까지 표현하였습니다. 



In [8]: df['id_3'] = df['id'].apply(lambda x: "{:.2f}".format(x))


In [9]: df





  (4) 'name' 변수의 문자열을 전부 대문자로 바꾼 새로운 변수 'name_3' 만들기


upper() 문자열 내장 메소드를 사용하여 소문자를 대문자로 변경하였습니다. 



In [10]: df['name_3'] = df['name'].apply(lambda x: x.upper())


In [11]: df

 




  (5) 데이터프레임 안의 'id_3'와 'name_3' 변수를 합쳐서 새로운 변수 'id_name_3' 만들기



In [14]: df['id_name_3'] = df[['id_3', 'name_3']].apply(lambda x: ':'.join(x), axis=1)


In [15]: df

 



많은 도움이 되었기를 바랍니다. 

Posted by R Friend R_Friend

이번 포스팅에서는 Python pandas의 DataFrame에서 범주형 변수의 항목(class)을 기준 정보(mapping table, reference table)를 이용하여 일괄 변환하는 방법을 소개하겠습니다. 


(1) 범주형 변수의 항목 매핑/변환에 사용한 기준 정보를 dict 자료형으로 만들어 놓고, 


(2) dict.get() 함수를 이용하여 매핑/변환에 사용할 사용자 정의 함수를 만든 후에 


(3) map() 함수로 (2)번에서 만든 사용자 정의 함수를 DataFrame의 범주형 변수에 적용하여 매핑하기



차근차근 예를 들어서 설명해보겠습니다. 


먼저, 간단한 예제 데이터프레임을 만들어보겠습니다. 



import pandas as pd

from pandas import DataFrame


df = DataFrame({'name': ['kim', 'KIM', 'Kim', 'lee', 'LEE', 'Lee', 'wang', 'hong'], 

                'value': [1, 2, 3, 4, 5, 6, 7, 8], 

                'value_2': [100, 300, 200, 100, 100, 300, 50, 80]

               })


df

namevaluevalue_2
0kim1100
1KIM2300
2Kim3200
3lee4100
4LEE5100
5Lee6300
6wang750
7hong880

 




위의 df 라는 이름의 DataFrame에서, name 변수의 (kim, KIM, Kim) 를 (kim)으로, (lee, LEE, Lee)를 (lee)로, 그리고 (wang, hong)을 (others) 라는 항목으로 매핑하여 새로운 변수 name_2 를 만들어보려고 합니다. 



  (1) 범주형 변수의 항목 매핑/변환에 사용할 기준 정보를 dict 자료형으로 만들기



name_mapping = {

    'KIM': 'kim',

    'Kim': 'kim', 

    'LEE': 'lee', 

    'Lee': 'lee', 

    'wang': 'others', 

    'hong': 'others'

}


name_mapping

 {'KIM': 'kim',

 'Kim': 'kim',
 'LEE': 'lee',
 'Lee': 'lee',
 'hong': 'others',
 'wang': 'others'}




  (2) dict.get() 함수를 이용하여 매핑/변환에 사용할 사용자 정의 함수 만들기


dict 자료형에 대해 dict.get() 함수를 사용하여 정의한 아래의 사용자 정의 함수 func는 '만약 매핑에 필요한 정보가 기준 정보 name_mapping dict에 있으면 그 정보를 사용하여 매핑을 하고, 만약에 기준정보 name_mapping dict에 매핑에 필요한 정보가 없으면 입력값을 그대로 반환하라는 뜻입니다. 'lee', 'kim'의 경우 위의 name_mapping dict 기준정보에 매핑에 필요한 정보항목이 없으므로 그냥 자기 자신을 그대로 반환하게 됩니다. 



func = lambda x: name_mapping.get(x, x)

 




  (3) map() 함수로 매핑용 사용자 정의 함수를 DataFrame의 범주형 변수에 적용하여 매핑/변환하기


위의 기준정보 name_mapping dict를 사용하여 'name_2' 라는 이름의 새로운 범주형 변수를 만들어보았습니다. 



df['name_2'] = df.name.map(func)


df

namevaluevalue_2name_2
0kim1100kim
1KIM2300kim
2Kim3200kim
3lee4100lee
4LEE5100lee
5Lee6300lee
6wang750others
7hong880others

 




  (4) groupby() 로 범주형 변수의 그룹별로 집계하기


범주형 변수에 대해서 항목을 매핑/변환하여 새로운 group 정보를 만들었으니, groupby() operator를 사용해서 새로 만든 name_2 변수별로 연속형 변수들('value', 'value_2')의 합계를 구해보겠습니다. 



# aggregation by name

df.groupby('name_2').sum()

valuevalue_2
name_2
kim6600
lee15500
others15130

 




'name_2'와 'name' 범주형 변수 2개를 groupby()에 함께 사용하여 두개 범주형 변수의 계층적인 인덱스(hierarchical index) 형태로 'value_2' 연속형 변수에 대해서만 합계를 구해보겠습니다. (아래의 결과에 대해 unstack()을 하면 name 변수를 칼럼으로 올려서 cross-tab 형태로 볼 수도 있겠습니다.)



df.groupby(['name_2', 'name'])['value_2'].sum()

name_2  name
kim     KIM     300
        Kim     200
        kim     100
lee     LEE     100
        Lee     300
        lee     100
others  hong     80
        wang     50
Name: value_2, dtype: int64

 



많은 도움이 되었기를 바랍니다. 


Posted by R Friend R_Friend

이번 포스팅에서는 GroupBy 를 사용하여 그룹별로 반복 작업(iteration over groups)하는 방법을 소개하겠습니다. 

pandas의 GroupBy 객체는 for loop 반복 시에 그룹 이름과 그룹별 데이터셋을 2개의 튜플로 반환합니다. 이러한 특성을 잘 활용하면 그룹별로 for loop 반복작업을 하는데 유용하게 사용할 수 있습니다. 


[ GroupBy로 그룹별로 반복 작업하기 ]




예제로 사용할 데이터는 UCI machine learning repository에 등록되어 있는 abalone 공개 데이터셋입니다. 



abalone = pd.read_csv("/Users/ihongdon/Documents/Python/abalone.txt", 

                      sep=",", 

                      names = ['sex', 'length', 'diameter', 'height', 

                               'whole_weight', 'shucked_weight', 'viscera_weight', 

                               'shell_weight', 'rings'], 

                      header = None)



abalone['length_cat'] = np.where(abalone.length > np.median(abalone.length), 

                                 'length_long', 

                                 'length_short')



abalone.head()

sexlengthdiameterheightwhole_weightshucked_weightviscera_weightshell_weightringslength_cat
0M0.4550.3650.0950.51400.22450.10100.15015length_short
1M0.3500.2650.0900.22550.09950.04850.0707length_short
2F0.5300.4200.1350.67700.25650.14150.2109length_short
3M0.4400.3650.1250.51600.21550.11400.15510length_short
4I0.3300.2550.0800.20500.08950.03950.0557length_short





위의 abalone 데이터셋을 '성별(sex)'로 GroupBy를 한 후에, for loop을 돌려서 그룹 이름(sex: 'F', 'I', 'M')별로 데이터셋을 프린트해보겠습니다. 



for sex, group_data in abalone[['sex', 'length_cat', 'whole_weight', 'rings']].groupby('sex'):

    print sex

    print group_data[:5]

 

F    sex    length_cat  whole_weight  rings

2 F length_short 0.6770 9 6 F length_short 0.7775 20 7 F length_short 0.7680 16 9 F length_long 0.8945 19 10 F length_short 0.6065 14

I    sex    length_cat  whole_weight  rings
4    I  length_short        0.2050      7
5    I  length_short        0.3515      8
16   I  length_short        0.2905      7
21   I  length_short        0.2255     10
42   I  length_short        0.0700      5

M    sex    length_cat  whole_weight  rings
0    M  length_short        0.5140     15
1    M  length_short        0.2255      7
3    M  length_short        0.5160     10
8    M  length_short        0.5095      9
11   M  length_short        0.4060     10





이번에는 두 개의 범주형 변수(sex, length_cat)를 사용하여 for loop 반복문으로 그룹 이름 (sex와 leggth_cat 의 조합: F & length_long, F & length_short, I & length_long, I & length_short, M & length_long, M & length_short)과 각 그룹별 데이터셋을 프린트해보겠습니다. 


참고로, 아래 코드에서 '\' 역슬래쉬는 코드를 한줄에 전부 다 쓰기에 너무 길 때 다음줄로 코드를 넘길 때 사용합니다. 



for (sex, length_cat), group_data in abalone[['sex', 'length_cat', 'whole_weight', 'rings']]\

.groupby(['sex', 'length_cat']):

    print sex, length_cat

    print group_data[:5]

 

F length_long
   sex   length_cat  whole_weight  rings
9    F  length_long        0.8945     19
22   F  length_long        0.9395     12
23   F  length_long        0.7635      9
24   F  length_long        1.1615     10
25   F  length_long        0.9285     11
F length_short
   sex    length_cat  whole_weight  rings
2    F  length_short        0.6770      9
6    F  length_short        0.7775     20
7    F  length_short        0.7680     16
10   F  length_short        0.6065     14
13   F  length_short        0.6845     10
I length_long
    sex   length_cat  whole_weight  rings
509   I  length_long        0.8735     16
510   I  length_long        1.1095     10
549   I  length_long        0.8750     11
550   I  length_long        1.1625     17
551   I  length_long        0.9885     13
I length_short
   sex    length_cat  whole_weight  rings
4    I  length_short        0.2050      7
5    I  length_short        0.3515      8
16   I  length_short        0.2905      7
21   I  length_short        0.2255     10
42   I  length_short        0.0700      5
M length_long
   sex   length_cat  whole_weight  rings
27   M  length_long        0.9310     12
28   M  length_long        0.9365     15
29   M  length_long        0.8635     11
30   M  length_long        0.9975     10
32   M  length_long        1.3380     18
M length_short
   sex    length_cat  whole_weight  rings
0    M  length_short        0.5140     15
1    M  length_short        0.2255      7
3    M  length_short        0.5160     10
8    M  length_short        0.5095      9
11   M  length_short        0.4060     10





다음으로, 성별(sex)로 GroupBy를 해서 성별 그룹('F', 'I', 'M')을 key로 하고, 데이터셋을 value로 하는 dict를 만들어보겠습니다. 



abalone_sex_group = dict(list(abalone[:10][['sex', 'length_cat', 'whole_weight', 'rings']]

                              .groupby('sex')))

 

abalone_sex_group


{'F':   sex    length_cat  whole_weight  rings
 2   F  length_short        0.6770      9
 6   F  length_short        0.7775     20
 7   F  length_short        0.7680     16
 9   F   length_long        0.8945     19,
 'I':   sex    length_cat  whole_weight  rings
 4   I  length_short        0.2050      7
 5   I  length_short        0.3515      8,
 'M':   sex    length_cat  whole_weight  rings
 0   M  length_short        0.5140     15
 1   M  length_short        0.2255      7
 3   M  length_short        0.5160     10
 8   M  length_short        0.5095      9}





이렇게 그룹 이름을 key로 하는 dict 를 만들어놓으면 그룹 이름을 가지고 데이터셋을 indexing하기에 편리합니다.  예로 성별 중에 'M'인 데이터셋을 indexing해보겠습니다. 



abalone_sex_group['M'] 

sexlengthdiameterheightwhole_weightshucked_weightviscera_weightshell_weightringslength_cat
0M0.4550.3650.0950.51400.22450.10100.15015length_short
1M0.3500.2650.0900.22550.09950.04850.0707length_short
3M0.4400.3650.1250.51600.21550.11400.15510length_short
8M0.4750.3700.1250.50950.21650.11250.1659length_short




물론 abalone[:10][abalone['sex'] == 'M']  처럼 원래의 처음 abalone 데이터프레임에 boolean 형태로 indexing을 해도 됩니다. 대신에 dict 로 만들어놓으면 데이터셋 indexing 하는 속도가 더 빠를겁니다. 


많은 도움이 되었기를 바랍니다. 

Posted by R Friend R_Friend

이번 포스팅에서는 Python pandas의 groupby() 연산자를 사용하여 집단, 그룹별로 데이터를 집계, 요약하는 방법을 소개하겠습니다. 


전체 데이터를 그룹 별로 나누고 (split), 각 그룹별로 집계함수를 적용(apply) 한후, 그룹별 집계 결과를 하나로 합치는(combine) 단계를 거치게 됩니다. (Split => Apply function => Combine)



[ GroupBy aggregation mechanics ]




groupby() 는 다양한 변수를 가진 데이터셋을 분석하는데 있어 그룹별로 데이터를 집계하는 분석은 일상적으로 이루어지는 만큼 사용빈도가 매우 높고 알아두면 유용합니다. 


실습에 사용할 예제는 바다 해산물인 전복(abalone)에 대한 공개 데이터셋을 사용하겠습니다. 



[ UCI Machine Learning Repository ]

  • Abalone CSV dataset download:   abalone.txt
  • Variables

    Name Data Type Meas. Description ---- --------- ----- ----------- Sex nominal M, F, and I (infant) Length continuous mm Longest shell measurement Diameter continuous mm perpendicular to length Height continuous mm with meat in shell Whole weight continuous grams whole abalone Shucked weight continuous grams weight of meat Viscera weight continuous grams gut weight (after bleeding) Shell weight continuous grams after being dried Rings integer +1.5 gives the age in years



먼저, 바로 위에 링크해놓은 abalone.txt를 다운받은 후에, abalone.txt 데이터셋을 pandas의 read_csv() 로 불러와서 DataFrame을 만들어보겠습니다. 



# Importing common libraries

import pandas as pd

from pandas import DataFrame

from pandas import Series

import numpy as np

 

# Reading abalone data set

abalone = pd.read_csv("/Users/ihongdon/Documents/Python/abalone.txt", 

                      sep=",", 

                      names = ['sex', 'length', 'diameter', 'height', 

                               'whole_weight', 'shucked_weight', 'viscera_weight', 

                               'shell_weight', 'rings'], 

                      header = None)





abalone 라는 이름의 pandas DataFrame을 만들었으니, 데이터가 어떻게 생겼는지 탐색해보겠습니다. 다행히 결측치는 없으며, 4,177개의 관측치를 가지고 있네요. 전복의 성별(sex) 변수가 범주형 변수입니다. 



# View of top 5 observations

abalone.head()


sex length diameter height whole_weight shucked_weight viscera_weight shell_weight rings

0 M 0.455 0.365 0.095 0.5140 0.2245 0.1010 0.150 15

1 M 0.350 0.265 0.090 0.2255 0.0995 0.0485 0.070 7

2 F 0.530 0.420 0.135 0.6770 0.2565 0.1415 0.210 9

3 M 0.440 0.365 0.125 0.5160 0.2155 0.1140 0.155 10

4 I 0.330 0.255 0.080 0.2050 0.0895 0.0395 0.055 7



# Check the missing value

np.sum(pd.isnull(abalone))


sex               0
length            0
diameter          0
height            0
whole_weight      0
shucked_weight    0
viscera_weight    0
shell_weight      0
rings             0
dtype: int64

 


# Descriptive statics

abalone.describe()

lengthdiameterheightwhole_weightshucked_weightviscera_weightshell_weightrings
count4177.0000004177.0000004177.0000004177.0000004177.0000004177.0000004177.0000004177.000000
mean0.5239920.4078810.1395160.8287420.3593670.1805940.2388319.933684
std0.1200930.0992400.0418270.4903890.2219630.1096140.1392033.224169
min0.0750000.0550000.0000000.0020000.0010000.0005000.0015001.000000
25%0.4500000.3500000.1150000.4415000.1860000.0935000.1300008.000000
50%0.5450000.4250000.1400000.7995000.3360000.1710000.2340009.000000
75%0.6150000.4800000.1650001.1530000.5020000.2530000.32900011.000000
max0.8150000.6500001.1300002.8255001.4880000.7600001.00500029.000000





자, 데이터 준비가 되었으니 이제부터 '전복 성별(sex)' 그룹('F', 'M', 'I')별로 전복의 전체 무게('whole_weight') 변수에 대해서 GroupBy 집계를 해보겠습니다. 


집단별 크기는 grouped.size(), 집단별 합계는 grouped.sum(), 집단별 평균은 grouped.mean() 을 사용합니다. 



grouped = abalone['whole_weight'].groupby(abalone['sex'])


grouped 

<pandas.core.groupby.SeriesGroupBy object at 0x112668c10>


grouped.size()

sex
F    1307
I    1342
M    1528
Name: whole_weight, dtype: int64


grouped.sum()

sex
F    1367.8175
I     578.8885
M    1514.9500
Name: whole_weight, dtype: float64


grouped.mean()

sex
F    1.046532
I    0.431363
M    0.991459
Name: whole_weight, dtype: float64





위의 예에서는 'whole_weight' 라는 하나의 연속형 변수에 대해서만 '성별(sex)' 집계를 하였습니다만, 집계를 하는 key를 제외한 데이터프레임 안의 전체 연속형 변수에 대해서 한꺼번에 집계를 할 수도 있습니다. 



abalone.groupby(abalone['sex']).mean()

lengthdiameterheightwhole_weightshucked_weightviscera_weightshell_weightrings
sex
F0.5790930.4547320.1580111.0465320.4461880.2306890.30201011.129304
I0.4277460.3264940.1079960.4313630.1910350.0920100.1281827.890462
M0.5613910.4392870.1513810.9914590.4329460.2155450.28196910.705497




DataFrame.groupby('key_var').func() 형식으로도 사용가능하며, 위의 abalone.groupby(abalone['sex']).mean()은 아래처럼 abalone.groupby('sex').mean() 처럼 써도 똑같은 결과를 얻을 수 있습니다. 



abalone.groupby('sex').mean()

lengthdiameterheightwhole_weightshucked_weightviscera_weightshell_weightrings
sex
F0.5790930.4547320.1580111.0465320.4461880.2306890.30201011.129304
I0.4277460.3264940.1079960.4313630.1910350.0920100.1281827.890462
M0.5613910.4392870.1513810.9914590.4329460.2155450.28196910.705497





이제부터는 '성별(sex)'  이외에 '길이(length)'를 가지고 범주형 변수를 하나 더 만들어서, 2개의 범주형 변수 key 값을 가지고 그룹별 집계를 해보겠습니다. 


np.where()  함수를 사용하여 length 의 중앙값보다 크면 'length_long'으로, 중앙값보다 작으면 'length_short'의 이름으로하는 계급으로하는 새로운 범주형 변수를 만들어보겠습니다. 



abalone['length_cat'] = np.where(abalone.length > np.median(abalone.length), 

                                 'length_long', # True

                                 'length_short') # False


abalone[['length', 'length_cat']][:10]


  length length_cat

0 0.455 length_short

1 0.350 length_short

2 0.530 length_short

3 0.440 length_short

4 0.330 length_short

5 0.425 length_short

6 0.530 length_short

7 0.545 length_short

8 0.475 length_short

9 0.550 length_long





그럼, 이제 성별 그룹(sex)과 길이 범주(length_cat) 그룹별로  GroupBy 를 사용하여 평균을 구해보겠습니다. 



mean_by_sex_length = abalone['whole_weight'].groupby([abalone['sex'], abalone['length_cat']]).mean()

 

mean_by_sex_length


sex  length_cat  
F    length_long     1.261330
     length_short    0.589702
I    length_long     0.923215
     length_short    0.351234
M    length_long     1.255182
     length_short    0.538157
Name: whole_weight, dtype: float64




위이 집계 결과가 SQL로 집계했을 때의 형태로 결과가 제시가 되었는데요, unstack() 함수를 사용하면 집계 결과를 가로, 세로 축으로 좀더 보기에 좋게 표현을 할 수 있습니다. 



mean_by_sex_length.unstack()

length_catlength_longlength_short
sex
F1.2613300.589702
I0.9232150.351234
M1.2551820.538157

 




abalone['whole_weight'].groupby([abalone['sex'], abalone['length_cat']]).mean() 를 좀더 간결하게 아래처럼 쓸 수도 있습니다. 대상 데이터프레임을 제일 앞에 써주고, groupby()에 집계의 기준이 되는 key 변수들을 써주고, 제일 뒤에 집계하려는 연속형 변수이름을 써주었습니다. 



abalone.groupby(['sex', 'length_cat'])['whole_weight'].mean()

 

sex  length_cat  
F    length_long     1.261330
     length_short    0.589702
I    length_long     0.923215
     length_short    0.351234
M    length_long     1.255182
     length_short    0.538157
Name: whole_weight, dtype: float64




많은 도움이 되었기를 바랍니다. 

Posted by R Friend R_Friend

가변수(dummy variable)는 해당 범주(category)에 해당하는 경우 '1', 해당하지 않는 경우 '0'으로 값을 입력해주어서 통계나 기계학습을 할 때 컴퓨터가 범주형 자료의 값을 인식할 수 있도록 해줍니다. 


이번 포스팅에서는 Python pandas 라이브러리의 get_dummies() 함수를 사용하여, 


(1) 하나의 cell 당 값이 한개씩 들어있는 범주형 자료를 가지고 가변수 만들기

(2) 하나의 cell 당 범주 값이 여러개씩 들어있는 범주형 자료를 가지고 가변수 만들기


를 해보겠습니다. 


첫번째 것는 간단하구요, 두번째 것은 하나의 cell 안에 들어있는 복수개의 범주형 자료들을 분할(split) 한고 가변수 만드는 작업을 해야 해서 복잡합니다.  첫번째 것은 이전 포스팅(http://rfriend.tistory.com/273)에서 한번 소개했던 적이 있었구요, 이번 포스팅은 두번째 것을 살펴보기 위해서 글을 씁니다. 



  (1) 하나의 cell 당 값이 한개씩 들어있는 범주형 자료를 가지고 가변수 만들기



먼저 필요한 라이브러리들을 불러오고, 음악별 장르를 매핑해놓은 간단한 예제 데이터프레임을 만들어보겠습니다. 



# importing libraries

import numpy as np

import pandas as pd

from pandas import DataFrame

from pandas import Series



# make an example DataFrame

music_df = DataFrame({'music_id': [1, 2, 3, 4, 5], 

                      'music_genre': ['rock', 

                                      'disco', 

                                      'pop', 

                                      'rock', 

                                      'pop']}

                      , columns = ['music_id', 'music_genre'])


In [3]: music_df

Out[3]:

   music_id    music_genre

0 1              rock

1 2              disco

2 3              pop

3 4              rock

4 5              pop

 



위의 범주형 값이 들어있는 'music_genre' 범주형 변수에 대해서 pandas의 get_dummies() 함수를 사용하여 가변수(dummy variable) 을 만들어보겠습니다. 



In [4]: music_dummy_mat = pd.get_dummies(music_df['music_genre'])


In [5]: music_dummy_mat

Out[5]:

     disco       pop      rock

0         0         0         1

1         1         0         0

2         0         1         0

3         0         0         1

4         0         1         0

 



이번에는 (a) 가변수의 변수 이름들 앞에 'genre_' 라는 접두사(prefix)를 붙이고, (b) 원래의 music_df 데이터프레임에다가 가변수를 생성하면서 만든 music_dummy_mat 데이터프레임을 join() 함수를 사용하여 합쳐보겠습니다. 



In [6]: music_dummy_mat = music_df.join(music_dummy_mat.add_prefix('genre_'))


In [7]: music_dummy_mat

Out[7]:

   music_id  music_genre   genre_disco  genre_pop  genre_rock

0       1       rock                0               0                1

1       2       disco               1               0                0

2       3       pop                0                1                0

3       4       rock                0                0                1

4       5       pop                0                1                0

 




  (2) 하나의 cell에 범주 값이 여러개씩 들어있는 범주형 자료를 가지고 가변수 만들기


음악 한개당 구분자는 수직바('|') 로 해서 복수개의 음악 장르 범주 값이 들어있는 예제 데이터프레임을 만들어보겠습니다.  



# making example DataFrame

music_multi_df = DataFrame({'music_id': [1, 2, 3, 4, 5], 

                      'music_genre': ['rock|punk rock|heavy metal', 

                                      'hip hop|reggae', 

                                      'pop|jazz|blues', 

                                      'disco|techo', 

                                      'rhythm and blues|blues|jazz']}

                      , columns = ['music_id', 'music_genre'])

 


In [9]: music_multi_df

Out[9]:

     music_id      music_genre

0      1             rock|punk rock|heavy metal

1      2             hip hop|reggae

2      3             pop|jazz|blues

3      4             disco|techo

4      5             rhythm and blues|blues|jazz




'music_genre' 변수의 각 값에 수직바('|')로 구분되어 묶여있는 여러개의 범주 값들을 split() 문자열 메소드를 사용하여 분리를 한 후에, set.union() 함수를 사용하여 각 음악 장르 범주 값들을 원소로 가지는 하나의 집합을 만들어 보겠습니다. 



In [10]: music_genre_iter = (set(x.split('|')) for x in music_multi_df.music_genre)


In [11]: music_genre_set = sorted(set.union(*music_genre_iter))


In [12]: music_genre_set

Out[12]:

['blues',

 'disco',

 'heavy metal',

 'hip hop',

 'jazz',

 'pop',

 'punk rock',

 'reggae',

 'rhythm and blues',

 'rock',

 'techo']

 



다음으로, np.zeros() 함수를 사용하여 music_multi_df 의 행의 개수만큼의 행과 music_genre_set 의 개수만큼의 열을 가지는 '0'으로 채워진 데이터프레임을 만들어보겠습니다.  '0'만 채워진 데이터프레임은 다음번에 가변수의 '1' 값을 채워나갈 빈 집으로 보면 되겠습니다. 



In [14]: indicator_mat = DataFrame(np.zeros((len(music_multi_df), len(music_genre_set))),

    ...: columns=music_genre_set)


In [15]: indicator_mat

Out[15]:

blues disco heavy metal hip hop jazz pop punk rock reggae \

0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0

1 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0

2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0

3 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0

4 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0


rhythm and blues rock techo

0 0.0 0.0 0.0

1 0.0 0.0 0.0

2 0.0 0.0 0.0

3 0.0 0.0 0.0

4 0.0 0.0 0.0  

 



이제 for loop 문을 사용하여 각 row 별로 music_genre 의 값을 순회하면서 split() 메소드로 분리를 한 다음에, 각 음악별로 해당 장르를 방금 위에서 '0'으로 자리를 채워두었던 indicator_mat 데이터프레임의 행, 열을 참조하여 해당 위치에 '1'의 값을 입력해주겠습니다. 



In [18]: for i, genre in enumerate(music_multi_df.music_genre):

              indicator_mat.loc[i, genre.split('|')] = 1


In [19]: indicator_mat

Out[19]:

     blues disco heavy metal hip hop jazz pop punk rock reggae \

0      0.0      0.0      1.0      0.0       0.0    0.0      1.0      0.0

1       0.0      0.0      0.0      1.0      0.0    0.0      0.0      1.0

2      1.0      0.0      0.0      0.0       1.0    1.0      0.0      0.0

3      0.0      1.0      0.0      0.0       0.0    0.0      0.0      0.0

4      1.0      0.0      0.0      0.0       1.0    0.0      0.0      0.0


     rhythm and blues      rock      techo

0      0.0                       1.0       0.0

1      0.0                       0.0       0.0

2      0.0                       0.0       0.0

3      0.0                       0.0       1.0

4      1.0                       0.0       0.0  

 



마지막으로, (a) 음악 장르 가변수의 앞 머리에 'genre_' 라는 접두사를 붙이고, (b) 원래의 'music_multi_df' 데이터프레임에 방금전에 새로 만든 'indicator_mat' 가변수 데이터프레임을 join() 함수를 이용하여 합쳐보겠습니다. 



In [20]: music_indicator_mat = music_multi_df.join(indicator_mat.add_prefix('genre_'))


In [21]: music_indicator_mat

Out[21]:

  music_id music_genre genre_blues genre_disco \

0 1 rock|punk rock|heavy metal 0.0 0.0

1 2 hip hop|reggae 0.0 0.0

2 3 pop|jazz|blues 1.0 0.0

3 4 disco|techo 0.0 1.0

4 5 rhythm and blues|blues|jazz 1.0 0.0


  genre_heavy metal genre_hip hop genre_jazz genre_pop genre_punk rock \

0 1.0 0.0 0.0 0.0 1.0

1 0.0 1.0 0.0 0.0 0.0

2 0.0 0.0 1.0 1.0 0.0

3 0.0 0.0 0.0 0.0 0.0

4 0.0 0.0 1.0 0.0 0.0


  genre_reggae genre_rhythm and blues genre_rock genre_techo

0 0.0 0.0 1.0 0.0

1 1.0 0.0 0.0 0.0

2 0.0 0.0 0.0 0.0

3 0.0 0.0 0.0 1.0

4 0.0 1.0 0.0 0.0  


 



많은 도움이 되었기를 바랍니다. 

Posted by R Friend R_Friend

이번 포스팅에서는 Python pandas 의 Series, DataFrame의 행(row)과 열(column)에 대해서

 

 - 생성 (creation)

 - 선택 (selection, slicing and indexing)

 - 삭제 (drop, delete)

 

하는 방법에 대해서 알아보겠습니다.

 

외부 데이터셋을 불러오거나 직접 만든 다음에 데이터 전처리하는데 있어 수시로 사용하는 가장 기본이 되는 데이터 조작 기법이 행, 열 생성, 선택, 삭제입니다.

 

그동안의 포스팅을 따라해보신 분이라면 이미 많이 익숙해졌을 텐데요, 체계적으로 정리도 해보고, 복습도 해볼 겸 예를 들어서 설명해보겠습니다.

 

 

 

 

 

  (1) Series 생성 및 Series 원소 선택 (element selection, indexing)

 

pd.Series() 를 써서 별도의 index label 이 없는 간단한 Series 를 만들어 보겠습니다.

(index는 0, 1, 2, ... 정수가 자동 부여됨)

 

 

# importing library

In [1]: import numpy as np


In [2]: import pandas as pd

 


# pd.Series with ndarrary data

In [3]: Seri = pd.Series([0., 1., 2., 3., 4.])


In [4]: Seri

Out[4]:

0    0.0
1    1.0
2    2.0
3    3.0
4    4.0
dtype: float64

 

 

 

 

이제 Series의 index 위치나 조건을 가지고 indexing 을 해보겠습니다.

 

 

# Slicing pd.Series like ndarray-like

In [5]: Seri[0]

Out[5]: 0.0


In [6]: Seri[:3]

Out[6]:

0    0.0
1    1.0
2    2.0
dtype: float64


In [7]: Seri[Seri >= Seri.mean()]

Out[7]:

2    2.0
3    3.0
4    4.0
dtype: float64


In [8]: Seri[[4, 2, 0]]

Out[8]:

4    4.0
2    2.0
0    0.0
dtype: float64

 

 

 

 

다음으로, index에 label을 할당해준 Series를 만들어보고, 특정 index label을 지정해서 indexing을 해보겠습니다.

 

 

# pd.Series with index name passed

In [9]: Seri_ix = pd.Series([0., 1., 2., 3., 4.], index=['a', 'b', 'c', 'd', 'e'])


In [10]: Seri_ix

Out[10]:

a    0.0
b    1.0
c    2.0
d    3.0
e    4.0
dtype: float64

 


# Slicing with index label

In [11]: Seri_ix[['a', 'b', 'e']]

Out[11]:

a    0.0
b    1.0
e    4.0
dtype: float64


In [12]: Seri_ix.get(['a', 'b', 'e']) # get() method

Out[12]:

a    0.0
b    1.0
e    4.0
dtype: float64

 

 

 

 

특정 index label 을 지정해서 값(value)을 할당해보겠습니다.

 

 

# set values by index label
In [13]: Seri_ix['a'] = 100


In [14]: Seri_ix

Out[14]:

a    100.0
b      1.0
c      2.0
d      3.0
e      4.0
dtype: float64

 

 

 

 

특정 index label 이 Series에 들어있는지 아닌지 확인 (boolean True, False) 해보겠습니다.

 

 

# check index label whether it is or is'not in Series

In [15]: 'a' in Seri_ix

Out[15]: True


In [16]: 'x' in Seri_ix

Out[16]: False

 

 

 

 

 

  (2) DataFrame 행과 열 생성, 선택, 삭제 (creation, selection, drop of row and column)

 

예제로 사용할 간단한 DataFrame을 dict 로 칼럼과 값을 매핑하고, index 를 지정해서 만들어보겠습니다. DataFrame.index 로 index 확인, DataFrame.columns 로 칼럼 확인할 수 있습니다.

 

 

# importing library and making an example DataFrame

In [17]: from pandas import DataFrame


In [18]: df = DataFrame({'C1': [0., 1., 2., 3.],

    ...: 'C2': [4., 5., 6., 7.],

    ...: 'C3': [8., 9., 10., np.nan]},

    ...: index=['R1', 'R2', 'R3', 'R4'])

    ...:


In [19]: df

Out[19]:

     C1   C2    C3
R1  0.0  4.0   8.0
R2  1.0  5.0   9.0
R3  2.0  6.0  10.0
R4  3.0  7.0   NaN

 


# the row and column labels

In [20]: df.index # row labels

Out[20]: Index(['R1', 'R2', 'R3', 'R4'], dtype='object')


In [21]: df.columns # column labels

Out[21]: Index(['C1', 'C2', 'C3'], dtype='object')

 

 

 

 

df_2 = DataFrame(df_1, index=['xx', 'xx'], columns=['xx', 'xx']) 형식처럼 기존 df_1에서 행과 열을 선별해서 df_2라는 새로운 DataFrame을 만들 수 있습니다.

 

 

In [22]: df_R1R3 = DataFrame(df, index=['R1', 'R3'])


In [23]: df_R1R3

Out[23]:

     C1   C2    C3
R1  0.0  4.0   8.0
R3  2.0  6.0  10.0


In [24]: df_C1C3 = DataFrame(df, columns=['C1', 'C3'])


In [25]: df_C1C3

Out[25]:

     C1    C3
R1  0.0   8.0
R2  1.0   9.0
R3  2.0  10.0
R4  3.0   NaN


In [26]: df_R3R1_C3C1 = DataFrame(df, index=['R3', 'R1'], columns=['C3', 'C1'])


In [27]: df_R3R1_C3C1

Out[27]:

      C3   C1
R3  10.0  2.0
R1   8.0  0.0

 

 

 

 

DataFrame에서 칼럼 이름을 지정해서 선별하는 방법은 아래 예시 처럼 df[['xx', 'xx']] 처럼 하면 됩니다.

 

 

# selecting columns from DataFrame

In [28]: df

Out[28]:

     C1   C2    C3
R1  0.0  4.0   8.0
R2  1.0  5.0   9.0
R3  2.0  6.0  10.0
R4  3.0  7.0   NaN


In [29]: df[['C1', 'C2']]

Out[29]:

     C1   C2
R1  0.0  4.0
R2  1.0  5.0
R3  2.0  6.0
R4  3.0  7.0

 

 

 

 

DataFrame에 새로운 칼럼을 만들기때 (1) df['new_column'] = ... 과 (2) df.assign(new_column = ... ) 의 두가지 방법이 있습니다.

 

 

# (1) making a new column

In [30]: df['C4'] = df['C1'] + df['C2']


In [31]: df

Out[31]:

     C1   C2    C3    C4
R1  0.0  4.0   8.0   4.0
R2  1.0  5.0   9.0   6.0
R3  2.0  6.0  10.0   8.0
R4  3.0  7.0   NaN  10.0

 

 

# (2-1) assign() method

In [32]: df = df.assign(C5 = df['C1']*df['C2'])


In [33]: df

Out[33]:

     C1   C2    C3    C4    C5
R1  0.0  4.0   8.0   4.0   0.0
R2  1.0  5.0   9.0   6.0   5.0
R3  2.0  6.0  10.0   8.0  12.0
R4  3.0  7.0   NaN  10.0  21.0

 

# (2-2) the same with the above

In [34]: df.assign(C5 = lambda x: x.C1*x.C2)

Out[34]:

     C1   C2    C3    C4    C5
R1  0.0  4.0   8.0   4.0   0.0
R2  1.0  5.0   9.0   6.0   5.0
R3  2.0  6.0  10.0   8.0  12.0
R4  3.0  7.0   NaN  10.0  21.0

 

 

 

 

DataFrame의 칼럼을 삭제하는 방법에는 (1) df.drop(['xx', 'xx'], 1) 과 (2) del df['xx'] 의 방법이 있습니다.  del df['xx']은 원본 데이터프레임에서 칼럼을 삭제합니다.

 

 

# drop 'C3' column : DataFrame.drop('Column', 1)

In [35]: df_drop_C4C5 = df.drop(['C4', 'C5'], 1)


In [36]: df_drop_C4C5

Out[36]:

     C1   C2    C3
R1  0.0  4.0   8.0
R2  1.0  5.0   9.0
R3  2.0  6.0  10.0
R4  3.0  7.0   NaN

 

 

# delete a column from original DataFrame : del DataFrame['column']

In [37]: df

Out[37]:

     C1   C2    C3    C4    C5
R1  0.0  4.0   8.0   4.0   0.0
R2  1.0  5.0   9.0   6.0   5.0
R3  2.0  6.0  10.0   8.0  12.0
R4  3.0  7.0   NaN  10.0  21.0

 

In [38]: del df['C4']  # delete 'C4' column from the original DataFrame df directly


In [39]: del df['C5']  # delete 'C5' column from the original DataFrame df directly


In [40]: df

Out[40]:

     C1   C2    C3
R1  0.0  4.0   8.0
R2  1.0  5.0   9.0
R3  2.0  6.0  10.0
R4  3.0  7.0   NaN

 

 

 

 

DataFrame의 행(row)과 열(column)을 선택할 때는 df.['xx'][0:2] 를 예를 들어 소개합니다.

 

 

In [42]: df

Out[42]:

     C1   C2    C3
R1  0.0  4.0   8.0
R2  1.0  5.0   9.0
R3  2.0  6.0  10.0
R4  3.0  7.0   NaN

 


# selecting column form DataFrame

In [43]: df['C1']

Out[43]:

R1    0.0
R2    1.0
R3    2.0
R4    3.0
Name: C1, dtype: float64


In [44]: df.C1

Out[44]:

R1    0.0
R2    1.0
R3    2.0
R4    3.0
Name: C1, dtype: float64

 

# selecting row from DataFrame

In [45]: df[0:2]

Out[45]:

     C1   C2   C3
R1  0.0  4.0  8.0
R2  1.0  5.0  9.0

 

# indexing 'column' and 'row' from DataFrame

In [46]: df['C1'][0:2]

Out[46]:

R1    0.0
R2    1.0
Name: C1, dtype: float64


In [47]: df.C1[0:2]

Out[47]:

R1    0.0
R2    1.0
Name: C1, dtype: float64

 

 

 

 

index label을 가지고 행(row) 선택할 때는 df.loc['xx'] 를 사용합니다.

 

 

# Select row by label : df.loc[label]

In [48]: df.loc['R1']

Out[48]:

C1    0.0
C2    4.0
C3    8.0
Name: R1, dtype: float64


In [49]: df.loc[['R1', 'R2']]

Out[49]:

     C1   C2   C3
R1  0.0  4.0  8.0
R2  1.0  5.0  9.0

 

 

 

 

index의 label 이 아니라 정수(integer)로 indexing을 하려면 df.iloc[int] 를 사용해야 합니다.  만약 df.loc[int]를 사용하면 TypeError 가 발생합니다.

 

 

# TypeError: cannot do label indexing on with these indexers [0] of <class 'int'>

In [50]: df.loc[0] # TypeError

TypeError: cannot do label indexing on <class 'pandas.indexes.base.Index'> with these indexers [0] of <class 'int'>

 

 

# Select row by interger location : df.iloc[loc]

In [51]: df.iloc[0]

Out[51]:

C1    0.0
C2    4.0
C3    8.0
Name: R1, dtype: float64


In [52]: df.iloc[0:2]

Out[52]:

     C1   C2   C3
R1  0.0  4.0  8.0
R2  1.0  5.0  9.0

 

 

 

 

DataFrame의 행(row) indexing할 때 df[0:2] 처럼 행의 범위를 ':'로 설정해주어도 됩니다.  df[0] 처럼 정수값을 지정하면 KeyError 납니다(이때는 df.iloc[0] 을 써야 함).

 

 

# KeyError: 0

In [53]: df[0]  # KeyError: 0

KeyError: 0

 

 

# Select rows : df[0:2]

In [54]: df[0:2]

Out[54]:

     C1   C2   C3
R1  0.0  4.0  8.0
R2  1.0  5.0  9.0

 

 

 

 

조건을 부여해서 열을 선택할 수도 있습니다.

 

 

# Select rows by boolean vector : df[bool_vec]

In [55]: df[df['C1'] <= 1.0]

Out[55]:

     C1   C2   C3
R1  0.0  4.0  8.0
R2  1.0  5.0  9.0

 

 

 

 

 

선택할 칼럼을 벡터 객체로 만들어 놓고, DataFrame에서 벡터 객체에 들어있는 칼럼만 선별해올 수도 있겠지요. 분석 프로세스를 자동화하려고 할 때 선행 분석 결과를 받아서 벡터 객체로 만들어 놓고, 이를 받아서 필요한 변수만 선별할 때 종종 사용하곤 합니다.

 


# Select columns by column vector : df[col_bool_vec]

In [56]: df_col_selector = ['C1', 'C2']


In [57]: df[df_col_selector]

Out[57]:

     C1   C2
R1  0.0  4.0
R2  1.0  5.0
R3  2.0  6.0
R4  3.0  7.0

 

 

 

많은 도움 되었기를 바랍니다.

 

 

 

 

 

 

 

 

Posted by R Friend R_Friend