Pandas Iterrows 함수 활용

Page content

강의 홍보

I. Iterrows의 개념

데이터 전처리를 진행할 때, 데이터프레임에서 행에 반복적으로 접근을 하면서 값을 추출하거나 또는 그 값을 조작하는 일이 발생한다. 예를 들면, 특정 컬럼 A의 값에서 대문자 A를 찾아내 소문자 b로 변경한다고 가정해보자. 이런 경우에는 언제나 For-loop를 통한 반복문 코드 작성을 만들어야 한다.

이럴 때 보다 효율적으로 접근하는 방법 중 하나가 iterrows()를 사용하는 경우이다.

import pandas as pd
import io
import requests
import pprint

url = 'https://raw.githubusercontent.com/chloevan/datasets/master/sports/baseball_stats.csv'
url=requests.get(url).content
baseball_stats = pd.read_csv(io.StringIO(url.decode('utf-8')))

pprint.pprint(baseball_stats.head())
  Team League  Year   RS   RA   W   OBP   SLG    BA  Playoffs  RankSeason  \
0  ARI     NL  2012  734  688  81  0.33  0.42  0.26         0         NaN   
1  ATL     NL  2012  700  600  94  0.32  0.39  0.25         1         4.0   
2  BAL     AL  2012  712  705  93  0.31  0.42  0.25         1         5.0   
3  BOS     AL  2012  734  806  69  0.32  0.41  0.26         0         NaN   
4  CHC     NL  2012  613  759  61  0.30  0.38  0.24         0         NaN   

   RankPlayoffs    G  OOBP  OSLG  
0           NaN  162  0.32  0.41  
1           5.0  162  0.31  0.38  
2           4.0  162  0.32  0.40  
3           NaN  162  0.33  0.43  
4           NaN  162  0.34  0.42  

II. 조건부 행 추출

드디어 Python 데이터 분석가로 보스턴 레드박스(BOS)야구팀에 취직을 했다고 가정을 해보자. 단장이 2008 ~ 2010년까지의 득점과 실점의 차이를 보고 싶다고 요청을 해왔다. 이럴 때 어떻게 해야 할까?

bos_df = baseball_stats[baseball_stats.Team == "BOS"].reset_index(drop = True)
pprint.pprint(bos_df.head())
  Team League  Year   RS   RA   W   OBP   SLG    BA  Playoffs  RankSeason  \
0  BOS     AL  2012  734  806  69  0.32  0.41  0.26         0         NaN   
1  BOS     AL  2011  875  737  90  0.35  0.46  0.28         0         NaN   
2  BOS     AL  2010  818  744  89  0.34  0.45  0.27         0         NaN   
3  BOS     AL  2009  872  736  95  0.35  0.45  0.27         1         3.0   
4  BOS     AL  2008  845  694  95  0.36  0.45  0.28         1         3.0   

   RankPlayoffs    G  OOBP  OSLG  
0           NaN  162  0.33  0.43  
1           NaN  162  0.32  0.39  
2           NaN  162  0.33  0.40  
3           4.0  162  0.34  0.42  
4           3.0  162  0.32  0.39  

이 때, 중요한 것 중의 하나는 .reset_index(drop = True) 활용법인데, 기존의 행 인덱스를 제거하고 0부터 다시 시작하는 것이 특징이다. 위 표에서 보는 것처럼 Team-BOS 데이터만 추출 된 것을 확인할 수 있다.

이제는 Year 컬럼에서 2008~2010년 데이터만 추출한다.

bos_year_df = bos_df[bos_df["Year"].isin([2008, 2009, 2010])].reset_index(drop = True)
pprint.pprint(bos_year_df.head())
  Team League  Year   RS   RA   W   OBP   SLG    BA  Playoffs  RankSeason  \
0  BOS     AL  2010  818  744  89  0.34  0.45  0.27         0         NaN   
1  BOS     AL  2009  872  736  95  0.35  0.45  0.27         1         3.0   
2  BOS     AL  2008  845  694  95  0.36  0.45  0.28         1         3.0   

   RankPlayoffs    G  OOBP  OSLG  
0           NaN  162  0.33  0.40  
1           4.0  162  0.34  0.42  
2           3.0  162  0.32  0.39  

이번에 소개하는 함수는 .isin()인데, 연구자가 원하는 값만 알면 쉽게 추출할 수 있다는 장점이 있다. R을 사용하는 유저라면 %in% 함수를 기억할 것인데, 이와 매우 유사하다.

III. Data Frame과 For-loop의 실체

Python DataFrame과 For-loop가 만나면 어떻게 작동을 할까? iterrows() 함수를 활용하여 실체를 한번 들여다 보자. 먼저 각 행을 각각 추출해본다.

for i,row in bos_year_df.iterrows():
    print(i)
    print(row)
    print(type(row))
0
Team             BOS
League            AL
Year            2010
RS               818
RA               744
W                 89
OBP             0.34
SLG             0.45
BA              0.27
Playoffs           0
RankSeason       NaN
RankPlayoffs     NaN
G                162
OOBP            0.33
OSLG             0.4
Name: 0, dtype: object
<class 'pandas.core.series.Series'>
1
Team             BOS
League            AL
Year            2009
RS               872
RA               736
W                 95
OBP             0.35
SLG             0.45
BA              0.27
Playoffs           1
RankSeason         3
RankPlayoffs       4
G                162
OOBP            0.34
OSLG            0.42
Name: 1, dtype: object
<class 'pandas.core.series.Series'>
2
Team             BOS
League            AL
Year            2008
RS               845
RA               694
W                 95
OBP             0.36
SLG             0.45
BA              0.28
Playoffs           1
RankSeason         3
RankPlayoffs       3
G                162
OOBP            0.32
OSLG            0.39
Name: 2, dtype: object
<class 'pandas.core.series.Series'>

DataFrame이 For-loop와 만나게 되면 각 loop에서 rowReturn Pandas Series 형태인 것을 확인할 수 있다. For-loop 안에서 데이터 처리를 할 때, Pandas Series 형태인 것을 감안하고 접근해야 한다는 뜻이다.

for row_tuple in bos_year_df.iterrows():
    print(row_tuple)
    print(type(row_tuple))
(0, Team             BOS
League            AL
Year            2010
RS               818
RA               744
W                 89
OBP             0.34
SLG             0.45
BA              0.27
Playoffs           0
RankSeason       NaN
RankPlayoffs     NaN
G                162
OOBP            0.33
OSLG             0.4
Name: 0, dtype: object)
<class 'tuple'>
(1, Team             BOS
League            AL
Year            2009
RS               872
RA               736
W                 95
OBP             0.35
SLG             0.45
BA              0.27
Playoffs           1
RankSeason         3
RankPlayoffs       4
G                162
OOBP            0.34
OSLG            0.42
Name: 1, dtype: object)
<class 'tuple'>
(2, Team             BOS
League            AL
Year            2008
RS               845
RA               694
W                 95
OBP             0.36
SLG             0.45
BA              0.28
Playoffs           1
RankSeason         3
RankPlayoffs       3
G                162
OOBP            0.32
OSLG            0.39
Name: 2, dtype: object)
<class 'tuple'>

이번에는 Tuple 형태로 데이터가 Return 했다. DataFrame와 For-loop가 만나면 이렇게 다양한 객체로 다시 Return하는 것을 보았다. Tuple로 결과값을 받을지, 아니면 Series 형태로 받을지는 미리 알고 써야 데이터 처리시의 에러에 잘 대처할 수 있다.

이번에는 득점과 실점을 계산한 후 기존 데이터에 다시 넣는 것을 해본다.

IV. 득점-실점 계산

# 함수 정의
def calc_diff(runs_scored, runs_allowed): # runs_scored: 득점 / runs_allowed: 실점
    run_diff = runs_scored - runs_allowed
    return run_diff

run_diffs = []
for i,row in bos_year_df.iterrows():
    runs_scored = row['RS']
    runs_allowed = row['RA']
    
    run_diff = calc_diff(runs_scored, runs_allowed)
    
    run_diffs.append(run_diff)

bos_year_df["RD"] = run_diffs
pprint.pprint(bos_year_df.head())
  Team League  Year   RS   RA   W   OBP   SLG    BA  Playoffs  RankSeason  \
0  BOS     AL  2010  818  744  89  0.34  0.45  0.27         0         NaN   
1  BOS     AL  2009  872  736  95  0.35  0.45  0.27         1         3.0   
2  BOS     AL  2008  845  694  95  0.36  0.45  0.28         1         3.0   

   RankPlayoffs    G  OOBP  OSLG   RD  
0           NaN  162  0.33  0.40   74  
1           4.0  162  0.34  0.42  136  
2           3.0  162  0.32  0.39  151  

새로운 컬럼 RD가 나타난 것을 확인할 수 있을 것이다. 오늘 배운 것은 iterrows()을 활용한 데이터 가공(Transformation)을 배웠다. 다음 시간에는 itertuples() 활용법에 대해 배우도록 한다.

V. Reference

pandas.DataFrame.iterrows¶. (n.d.). Retrieved March 20, 2020, from https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.iterrows.html?highlight=iterrows

End of Document