• #강의노트에서 이후 추가로 수정해야 할 사항: Pandas Introduction 1 ~ 4 내용과 10 min 내용을 종합적으로 정리할 필요 있음.

주의: 위 주석은 독자용이 아님.

Pandas 소개

앞서 살펴 보았듯이 pandas 모듈은 확률과 통계에 최적화된 파이썬 모듈이다. 특히, 데이터프레임(DataFrame) 자료형 클래스는 데이터 분석을 위한 다양한 기능을 제공한다. 데이터프레임 자료형의 기본 특성은 다음과 같다.

  • 스프레드시트라고 불리는 엑셀 파일에 담긴 테이블을 모방하는 자료형이다.
  • 엑셀에서 제공하는 다양한 기능을 기본 함수(메소드)로 제공한다.
  • 인덱싱, 슬라이싱 기능은 넘파이 모듈의 2차원 어레이와 기본적으로 유사하게 작동한다.
  • SQL이 데이터베이스를 다루는 기능과 유사한 기능 제공

pandas 기초 자료 안내

pandas의 기초적인 활용에 대해서는 아래 두 사이트를 언급하는 것으로 하고 넘어간다. 강의 시간에 일부 내용을 함께 확인할 예정이다.

먼저 아래 사이트의 내용 중 5.2절까지의 내용을 먼저 본다.

그 후에 아래 사이트 내용을 한 번 훑어 본다.

위 사이트의 소스코드는 아래 사이트를 참조하면 쉽게 얻을 수 있다.

https://github.com/liganega/10-minutes-to-pandas/blob/master/notebooks/10-minutes-to-pandas.ipynb

이제 다시 아내 사이트의 내용 중 5.2절 이후를 살펴본다.

강의노트로 돌아와서 GongSu21 장 내용을 다시 한 번 살펴본다.

안내

아래 내용은 다음 사이트를 참조하여 작성하였음.

http://sinpong.tistory.com/category/Python%20for%20data%20analysis


In [1]:
from pandas import Series, DataFrame
import pandas as pd
import numpy as np

pd는 pandas를 지칭하며 Series와 DataFrame은 원래 pandas 모듈에서 정의된 함수들이어서 기본적으로 pd.Series() 또는 pd.DataFrame() 형식으로 호출해야 한다. 하지만 많이 사용되는 함수들이기에 두 함수를 따로 임포트 하면 "pd." 부분은 생략이 가능하다. 즉, 로컬 네임스페이스로 import하는 것이 편해서 이렇게 사용한다.

pandas에 대해서 알아보려면 Series와 DataFrame, 이 두 가지 자료 구조에 익숙해져야 한다.

시리즈(Series) 자료형

Series는 넘파이의 1차원 어레이와 비슷한 자료형이다. 각각의 항목은 임의의, 하지만 동일한 자료형을 가져야 한다. 어레이와 다른 점은 사용자가 지정할 수 있는 색인들의 목록인 index가 항상 함께 사용된다는 점이다.

시리즈 생성: 어레이 및 리스트 활용

시리즈를 다양한 방식으로 생성할 수 있다. 먼저 어레이 및 리스트 활용하여 시리즈를 생성하는 것을 살펴 본다.


In [4]:
s1 = Series([4, -7, -5, 3])
s1


Out[4]:
0    4
1   -7
2   -5
3    3
dtype: int64

index를 지정하지 않으면 어레이 인덱싱에서 사용되는 숫자가 자동으로 사용된다.

  • 색인은 0부터 시작한다.

값(values)과 인덱스(index) 속성

시리즈(Series)는 값들의 어레이와 색인들의 목록으로 구성되며, 각각을 values와 index 속성을 통해 확인할 수 있다.


In [5]:
s1.values


Out[5]:
array([ 4, -7, -5,  3], dtype=int64)

In [6]:
s1.index


Out[6]:
RangeIndex(start=0, stop=4, step=1)

index 지정

색인들의 목록을 사용자가 임의로 지정하면서 시리즈를 생성할 수 있다.


In [3]:
s2 = Series([4, -7, -5, 3], index=['a', 'b', 'c', 'd'])
s2


Out[3]:
a    4
b   -7
c   -5
d    3
dtype: int64

index를 확인하면 기본 인덱스와 다른 자료형이 사용되었음을 확인할 수 있다.


In [6]:
s2.index


Out[6]:
Index([u'a', u'b', u'c', u'd'], dtype='object')

색인은 대입을 통해서도 변경할 수 있다.


In [7]:
s2.index = ['A', 'B', 'C', 'D']
s2


Out[7]:
A    4
B   -7
C   -5
D    3
dtype: int64

인덱싱

시리즈 인덱싱은 기본적으로 어레이 인덱싱과 비슷하다.


In [8]:
s2['C']


Out[8]:
-5

여러 개의 색인을 활용하여 인덱싱을 하면 시리즈 값이 리턴된다.

  • 리스트를 색인들의 목록으로 활용한다.
  • 사용된 색인 순서에 맞추어 시리즈가 결정된다.

In [8]:
s3 = s2[['D', 'A', 'B']]
s3


Out[8]:
D    3
A    4
B   -7
dtype: int64

마스크 인덱싱

넘파이 어레이에서의 마스크 인덱싱 기능을 거의 동일하게 활용할 수 있다.


In [10]:
mask = s2 > 0
mask


Out[10]:
A     True
B    False
C    False
D     True
dtype: bool

In [11]:
s2[mask]


Out[11]:
A    4
D    3
dtype: int64

시리즈 기본 연산

시리즈 연산은 기본적으로 어레이의 연산과 동일하다.

  • 기본적으로 항목별로 연산이 작동한다.
  • index 는 기본적으로 변하지 않는다.
  • 두 시리즈의 합은 인덱스의 존재 여부에 많은 영향을 받는다.

시리즈 관련 보다 다양한 연산 및 기능에 대해서는 추후에 자세히 다룰 예정이다.


In [12]:
s2 * 2


Out[12]:
A     8
B   -14
C   -10
D     6
dtype: int64

In [13]:
def f(x):
    return x/2 + 1/2

In [14]:
f(s2)


Out[14]:
A    2.0
B   -3.5
C   -2.5
D    1.5
dtype: float64

특정 색인 사용 여부 판단

in 연산자를 활용하여 특정 색인의 사용여부를 판단할 수 있다.


In [15]:
'B' in s2


Out[15]:
True

In [16]:
'one' in s2


Out[16]:
False

시리즈 생성: 사전 활용

시리즈 자료형은 사전 자료형과 매우 비슷하다. 다만 values에 동일한 자료형이 사용되어야 한다는 점에 다르다. 따라서 사전 자료형을 이용하여 시리즈를 쉽게 생성할 수 있다.


In [17]:
dic1 = {'Oh':2300, 'Ts': 1700, 'Or':1600, 'Ah':4500}
s4  = Series(dic1)
s4


Out[17]:
Ah    4500
Oh    2300
Or    1600
Ts    1700
dtype: int64

새로운 index를 사용할 경우, 기존의 사전에 사용되지 않은 key에는 값이 누락되었다는 의미로 NaN이 사용된다.

주의: NaN은 Not a Number의 줄임말로 어떤 값도 할당되지 않았음, 즉 널(Null)임을 의미한다.


In [18]:
keys1 = ['Ca', 'Oh', 'Or', 'Ts', 'Gg']
s5 = Series(dic1, index=keys1)
s5


Out[18]:
Ca       NaN
Oh    2300.0
Or    1600.0
Ts    1700.0
Gg       NaN
dtype: float64

널(null) 값 확인 함수

isnullnotnull 함수는 누락된 데이터의 위치를 확인할 때 사용한다.

두 함수 모두 시리즈 자료형을 리턴한다.


In [19]:
pd.isnull(s5)


Out[19]:
Ca     True
Oh    False
Or    False
Ts    False
Gg     True
dtype: bool

In [20]:
pd.notnull(s5)


Out[20]:
Ca    False
Oh     True
Or     True
Ts     True
Gg    False
dtype: bool

시리즈의 합

시리즈의 연산은 동일한 색인에 대해서만 기본적으로 값의 합이 이루어진다. 아래의 경우는 널값이 사용된다.

  • 두 시리즈에서 동시에 사용된 색인이 아닌 경우
  • 두 시리즈에서 동시에 색인으로 사용되었지만 최소 하나의 경우에서 널값을 갖는 경우

In [21]:
s4


Out[21]:
Ah    4500
Oh    2300
Or    1600
Ts    1700
dtype: int64

In [22]:
s5


Out[22]:
Ca       NaN
Oh    2300.0
Or    1600.0
Ts    1700.0
Gg       NaN
dtype: float64

In [23]:
s4 + s5


Out[23]:
Ah       NaN
Ca       NaN
Gg       NaN
Oh    4600.0
Or    3200.0
Ts    3400.0
dtype: float64

name 속성

name 속성을 이용하여 Series와 index에 이름을 지정할 수 있다.

Series 의 name 속성 설정


In [24]:
s5.name = 'Population'

index 의 name 속성 설정

index의 자료형이 Index 이며, Index 클래스에 name 속성을 변경해주어야 한다.


In [26]:
s5.index


Out[26]:
Index([u'Ca', u'Oh', u'Or', u'Ts', u'Gg'], dtype='object')

In [27]:
s5.index.name = 'State'

이제 s5의 name 속성과 s5.index의 속성이 설정되었음을 아래와 같이 확인할 수 있다.


In [28]:
s5


Out[28]:
State
Ca       NaN
Oh    2300.0
Or    1600.0
Ts    1700.0
Gg       NaN
Name: Population, dtype: float64

데이터프레임(DataFrame) 자료형

데이터프레임 자료형은 동일한 색인 목록(index)을 공유하는 여러 개의 시리즈를 붙혀 놓은 자료형으로 생각할 수 있다. 내부적으로는 행렬 모양의 2차원 어레이로 취급된다.

앞서 다룬 Weed_Price.csv 파일을 읽어 드렸을 때 사용되는 모습을 생각하면 여러 개의 Series를 붙혀놓은 모습이 데이터프레임이라는 것을 쉽게 이해할 수 있다.


In [30]:
weed_pd = pd.read_csv("data/Weed_Price.csv", parse_dates=[-1])
weed_pd.head()


Out[30]:
State HighQ HighQN MedQ MedQN LowQ LowQN date
0 Alabama 339.06 1042 198.64 933 149.49 123 2014-01-01
1 Alaska 288.75 252 260.60 297 388.58 26 2014-01-01
2 Arizona 303.31 1941 209.35 1625 189.45 222 2014-01-01
3 Arkansas 361.85 576 185.62 544 125.87 112 2014-01-01
4 California 248.78 12096 193.56 12812 192.92 778 2014-01-01

weed_pd에 할당된 데이터프레임에는 총 8개의 Series가 사용되었다. 각각의 시리즈의 이름(name)은 다음과 같다.

State, HighQ, HighQN, MedQ, MedQN, LowQ, LowQN, date

또한 언급된 8개의 시리즈의 index는 모두 기본 index를 사용하고 있다.

데이터프레임 생성: 사전 활용

아래의 경우처럼 키값이 동일한 길이의 리스트 또는 어레이인 사전을 활용하여 DataFrame을 생성할 수 있다.


In [31]:
data = {'state' : ['Ohio', 'Ohio', 'Ohio', 'Nevada', 'Nevada'],\
        'year' : [2000, 2001, 2002, 2001, 2002],\
        'pop' : [1.5, 1.7, 3.6, 2.4, 2.9]}

In [29]:
df = DataFrame(data)
df


Out[29]:
pop state year
0 1.5 Ohio 2000
1 1.7 Ohio 2001
2 3.6 Ohio 2002
3 2.4 Nevada 2001
4 2.9 Nevada 2002

사전 자료형을 이용하였기 때문에 시리즈의 순서가 임의로 지정되었다. 특정 순서로 시리즈를 나열하려면 columns 키워드 인자를 이용해야 한다.


In [30]:
DataFrame(data, columns=['year', 'state', 'pop'])


Out[30]:
year state pop
0 2000 Ohio 1.5
1 2001 Ohio 1.7
2 2002 Ohio 3.6
3 2001 Nevada 2.4
4 2002 Nevada 2.9

Series의 경우처럼 index를 지정할 수 있다.


In [34]:
df2 = DataFrame(data, index=['one','two','three','four','five'])
df2


Out[34]:
pop state year
one 1.5 Ohio 2000
two 1.7 Ohio 2001
three 3.6 Ohio 2002
four 2.4 Nevada 2001
five 2.9 Nevada 2002

데이터프레임 생성: 데이터프레임 활용

기존의 데이터프레임을 활용하여 새로운 데이터프레임을 생성할 수 있다.


In [35]:
df3 = DataFrame(df2)
df3


Out[35]:
pop state year
one 1.5 Ohio 2000
two 1.7 Ohio 2001
three 3.6 Ohio 2002
four 2.4 Nevada 2001
five 2.9 Nevada 2002

아래 코드는 기존의 데이터프레임에 컬럼을 확장하는 방식으로 새로운 데이터프레임을 생성한다.

주의: 새 컬럼에 값을 지정하지 않으므로 널값이 할당된다.


In [36]:
df4 = DataFrame(df3, columns=['year', 'state', 'pop', 'debt'])
df4


Out[36]:
year state pop debt
one 2000 Ohio 1.5 NaN
two 2001 Ohio 1.7 NaN
three 2002 Ohio 3.6 NaN
four 2001 Nevada 2.4 NaN
five 2002 Nevada 2.9 NaN

컬럼의 이름의 목록은 columns 속성에 저장되어 있다.


In [37]:
df4.columns


Out[37]:
Index([u'year', u'state', u'pop', u'debt'], dtype='object')

칼럼별 인덱싱

  • 컬럼의 이름을 키로 사용하여 인덱싱을 한다.

In [38]:
df4['year']


Out[38]:
one      2000
two      2001
three    2002
four     2001
five     2002
Name: year, dtype: int64

각각의 컬럼이 Series 자료형임을 확인할 수 있다.


In [39]:
type(df4['year'])


Out[39]:
pandas.core.series.Series
  • 각각의 컬럼의 이름(name)이 속성으로 지정되어 있기 때문에 속성으로 확인할 수도 있다.

In [41]:
df4.year


Out[41]:
one      2000
two      2001
three    2002
four     2001
five     2002
Name: year, dtype: int64

컬럼 값 지정하기

컬럼 인덱싱을 사용하여 값을 지정할 수 있다. 아래 코드는 debt 컬럼에 일정한 값을 지정할 때 사용한다.


In [43]:
df4['debt'] = 16.5
df4


Out[43]:
year state pop debt
one 2000 Ohio 1.5 16.5
two 2001 Ohio 1.7 16.5
three 2002 Ohio 3.6 16.5
four 2001 Nevada 2.4 16.5
five 2002 Nevada 2.9 16.5

아래 코드는 index의 길이와 동일한 크기의 어레이나 리스트를 활용하는 방법이다.


In [44]:
df4['debt'] = np.arange(5.)
df4


Out[44]:
year state pop debt
one 2000 Ohio 1.5 0.0
two 2001 Ohio 1.7 1.0
three 2002 Ohio 3.6 2.0
four 2001 Nevada 2.4 3.0
five 2002 Nevada 2.9 4.0

주의: 정수 5 대신에 부동소수점 5.를 사용하는 이유는 debt 컬럼의 자료형을 float로 설정하기 위함이다.


In [45]:
df4.dtypes


Out[45]:
year       int64
state     object
pop      float64
debt     float64
dtype: object

특정 컬럼의 데이터를 Series를 이용하여 지정할 때는 DataFrame의 색인에 따라 값이 대입되며 없는 색인에는 값이 대입되지 않는다.


In [46]:
val = Series([-1.2, -1.5, -1.7], index=['two', 'four', 'five'])
val


Out[46]:
two    -1.2
four   -1.5
five   -1.7
dtype: float64

In [47]:
df4['debt'] = val
df4


Out[47]:
year state pop debt
one 2000 Ohio 1.5 NaN
two 2001 Ohio 1.7 -1.2
three 2002 Ohio 3.6 NaN
four 2001 Nevada 2.4 -1.5
five 2002 Nevada 2.9 -1.7

행별 인덱싱

  • 행별 인덱싱은 색인 이름 또는 0, 1, 2, 등의 기본 색인을 이용한다.

색인 이름 인덱싱

  • loc 메소드 활용
  • loc은 location(위치)의 줄임말이다.

In [48]:
df4.loc['three']


Out[48]:
year     2002
state    Ohio
pop       3.6
debt      NaN
Name: three, dtype: object

loc의 리턴값은 시리즈이다.


In [49]:
type(df4.loc['three'])


Out[49]:
pandas.core.series.Series

컬럼의 이름이 index로 사용되었음에 주의한다.


In [50]:
df4.loc['three'].index


Out[50]:
Index([u'year', u'state', u'pop', u'debt'], dtype='object')

행별 값 지정

컬럼의 개수와 컬럼별 자료형과 동일한 값들을 사용하는 리스트를 활용하여 행별 값을 설정할 수 있다.


In [51]:
df4.loc['three'] = [2017, 'GG', 2.3, 3.0]
df4


Out[51]:
year state pop debt
one 2000 Ohio 1.5 NaN
two 2001 Ohio 1.7 -1.2
three 2017 GG 2.3 3.0
four 2001 Nevada 2.4 -1.5
five 2002 Nevada 2.9 -1.7

컬럼 추가

없는 칼럼을 대입하면 새로운 칼럼이 생성된다.

참고: eastern은 부활절을 의미한다.


In [47]:
df4['eastern']= (df4.state == 'Ohio')
df4


Out[47]:
year state pop debt eastern
one 2000 Ohio 1.5 NaN True
two 2001 Ohio 1.7 -1.2 True
three 2017 GG 2.3 3.0 False
four 2001 Nevada 2.4 -1.5 False
five 2002 Nevada 2.9 -1.7 False

참고: state == 'ohio'는 시리즈를 생성한다.


In [48]:
df4.state == 'Ohio'


Out[48]:
one       True
two       True
three    False
four     False
five     False
Name: state, dtype: bool

컬럼 삭제

파이썬 사전형에서와 마찬가지로 del 함수를 사용해서 칼럼을 삭제할 수 있다.


In [49]:
del df4['eastern']
df4


Out[49]:
year state pop debt
one 2000 Ohio 1.5 NaN
two 2001 Ohio 1.7 -1.2
three 2017 GG 2.3 3.0
four 2001 Nevada 2.4 -1.5
five 2002 Nevada 2.9 -1.7

인덱싱과 뷰 방식

DataFrame의 색인을 이용해서 생성된 칼럼은 내부 데이터에 대한 뷰(view)이며 복사가 이루어지지 않는다. 따라서 이렇게 얻은 Series 객체에 대한 변경은 실제 DataFrame에 반영된다. 복사본이 필요할 때는 Series의 copy 메서드를 이용하자.


In [50]:
df4


Out[50]:
year state pop debt
one 2000 Ohio 1.5 NaN
two 2001 Ohio 1.7 -1.2
three 2017 GG 2.3 3.0
four 2001 Nevada 2.4 -1.5
five 2002 Nevada 2.9 -1.7

In [51]:
debt_col = df4.debt
debt_col


Out[51]:
one      NaN
two     -1.2
three    3.0
four    -1.5
five    -1.7
Name: debt, dtype: float64

아래와 같이 인덱싱을 사용하여 값을 변경할 수는 있지만 경고문이 뜬다. 경고문은 슬라이싱(인덱싱) 결과에 수정을 가할 때 조심해야 한다는 내용이다.


In [52]:
debt_col.loc['one'] = 1.2


/Users/gslee/anaconda/lib/python2.7/site-packages/pandas/core/indexing.py:179: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
  self._setitem_with_indexer(indexer, value)

하지만 값이 기존의 df4까지 영향을 주는 것을 아래와 같이 확인할 수 있다. 위 경고문의 내용처럼 뷰 방식으로 작동하는 경우 데이터를 수정할 때 매우 조심해야 한다.


In [53]:
df4


Out[53]:
year state pop debt
one 2000 Ohio 1.5 1.2
two 2001 Ohio 1.7 -1.2
three 2017 GG 2.3 3.0
four 2001 Nevada 2.4 -1.5
five 2002 Nevada 2.9 -1.7

copy() 메소드를 사용하면 앞서 설명한 문제는 발생하지 않는다.


In [54]:
debt_col_copy = df4.debt.copy()

debt_col_copy의 데이터를 수정하자. 더 이상 경고문이 뜨지 않는다.


In [55]:
debt_col_copy.loc['one'] = -1.2

또한 기존의 df4가 변경되지 않았음을 확인할 수 있다.


In [56]:
df4


Out[56]:
year state pop debt
one 2000 Ohio 1.5 1.2
two 2001 Ohio 1.7 -1.2
three 2017 GG 2.3 3.0
four 2001 Nevada 2.4 -1.5
five 2002 Nevada 2.9 -1.7

데이터프레임 생성: 중첩 사전 활용

  • 중첩 사전을 이용하여 데이터프레임을 생성할 수 있다.

In [2]:
pop = {'Nevada' : {2001: 2.4, 2002: 2.9},
       'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}

바깥에 있는 사전의 키 값이 칼럼이 되고 안에 있는 키는 인덱스가 된다.


In [3]:
df5 = DataFrame(pop)
df5


Out[3]:
Nevada Ohio
2000 NaN 1.5
2001 2.4 1.7
2002 2.9 3.6
  • 색인을 직접 지정한다면 지정된 색인으로 DataFrame을 생성한다.

In [4]:
DataFrame(pop, index=[2001, 2002, 2003])


Out[4]:
Nevada Ohio
2001 2.4 1.7
2002 2.9 3.6
2003 NaN NaN
  • Series 객체를 담고 있는 사전 데이터도 같은 방식으로 취급된다.

In [5]:
df5['Ohio'][:-1]


Out[5]:
2000    1.5
2001    1.7
Name: Ohio, dtype: float64

In [6]:
df5['Nevada'][:2]


Out[6]:
2000    NaN
2001    2.4
Name: Nevada, dtype: float64

In [7]:
pdata = {'ohio' : df5['Ohio'][:-1],
         'Nevada': df5['Nevada'][:2]}
DataFrame(pdata)


Out[7]:
Nevada ohio
2000 NaN 1.5
2001 2.4 1.7

전치행렬 활용

넘파이에서와 마찬가지로 행과 열을 바꿀 수 있다.

주의

전치행렬이 뷰 방식을 따른다. 따라서 기본적으로 copy() 함수를 사용하여 기존 데이터와의 관계를 끊는 게 좋다.


In [8]:
df5T = df5.T.copy()
df5T


Out[8]:
2000 2001 2002
Nevada NaN 2.4 2.9
Ohio 1.5 1.7 3.6

In [9]:
df5['Nevada'].iloc[0] = 1.0
df5


Out[9]:
Nevada Ohio
2000 1.0 1.5
2001 2.4 1.7
2002 2.9 3.6

In [10]:
df5T


Out[10]:
2000 2001 2002
Nevada NaN 2.4 2.9
Ohio 1.5 1.7 3.6

name 속성

name 속성을 이용하여 컬럼과 index에 이름을 지정할 수 있다.


In [11]:
df5


Out[11]:
Nevada Ohio
2000 1.0 1.5
2001 2.4 1.7
2002 2.9 3.6

In [12]:
df5.index.name = 'year'
df5.columns.name = 'state'
df5


Out[12]:
state Nevada Ohio
year
2000 1.0 1.5
2001 2.4 1.7
2002 2.9 3.6

값(values) 속성

Series와 유사하게 values 속성은 DataFrame에 저장된 데이터를 2차원 배열로 반환한다.


In [67]:
df5.values


Out[67]:
array([[ 1. ,  1.5],
       [ 2.4,  1.7],
       [ 2.9,  3.6]])

DataFrame의 칼럼에 서로 다른 dtype이 있다면 모든 칼럼을 수용하기 위해 object라는 dtype이 선택된다. object를 만능 자료형이라 생각하면 편하다. 실제로는 4개의 포인터로 구성된다.


In [68]:
df3.values


Out[68]:
array([[1.5, 'Ohio', 2000],
       [1.7, 'Ohio', 2001],
       [3.6, 'Ohio', 2002],
       [2.4, 'Nevada', 2001],
       [2.9, 'Nevada', 2002]], dtype=object)