이번 시간에는 Pandas
의 다양한 기능에 대해 공부한다.
Pandas
Pandas(판다스)는 구조화된 데이터를 처리하는 파이썬 라이브러리이다. 쉽게 생각해서 파이선계의 엑셀이라고 보면 된다. 넘파이의 다양한 기능도 포함하고 있다.
데이터 불러오기
판다스로 데이터를 불러오는 과정은 다음과 같다.
>>> import pandas as pd
>>> data_url = "https://archive.ics.uci.edu/ml/machine-learning-databases/housing/housing.data"
>>> df_data = pd.read_csv(data_url, sep = "\s+", header = None)
>>> df_data.head()
0 1 2 3 4 5 6 7 8 9 10 11 12 13
0 0.00632 18.0 2.31 0 0.538 6.575 65.2 4.0900 1 296.0 15.3 396.90 4.98 24.0
1 0.02731 0.0 7.07 0 0.469 6.421 78.9 4.9671 2 242.0 17.8 396.90 9.14 21.6
2 0.02729 0.0 7.07 0 0.469 7.185 61.1 4.9671 2 242.0 17.8 392.83 4.03 34.7
3 0.03237 0.0 2.18 0 0.458 6.998 45.8 6.0622 3 222.0 18.7 394.63 2.94 33.4
4 0.06905 0.0 2.18 0 0.458 7.147 54.2 6.0622 3 222.0 18.7 396.90 5.33 36.2
판다스의 구성
판다스의 구성은 다음과 같다.
Dataframe은 전체 데이터를 의미한다. Series는 Dataframe 중 하나의 열에 해당하는 데이터의 모음이다.
Series 다루기
Series를 만드는 방법을 알아보자.
>>> from pandas import Series, DataFrame
>>> import pandas as pd
>>> list_data = [1, 2, 3, 4, 5]
>>> example_Obj = Series(data = list_data)
>>> example_Obj
0 1
1 2
2 3
3 4
4 5
dtype: int64
Series는 위에서 보이는 것처럼 인덱스(index)와 값(value)으로 나누어져 있다. 인덱스의 이름을 지정하는 것도 가능하다.
>>> list_data = [1, 2, 3, 4, 5]
>>> list_name = ['a', 'b', 'c', 'd', 'e']
>>> example_obj = Series(data = list_data, index = list_name)
>>> example_obj
a 1
b 2
c 3
d 4
e 5
데이터에 접근하는 방법과 데이터 인덱스에 값을 할당하는 방법은 다음과 같다.
>>> example_obj['a'] # 데이터에 접근
1
>>> example_obj['a'] = 32 # 데이터 값 할당
>>> example_obj
a 32
b 2
c 3
d 4
e 5
dtype: int64
다음과 같이 딕셔너리를 이용해 Series를 만드는 것도 가능하다.
>>> dict_data_1 = {'a': 1, 'b': 2, 'c': 3, 'd':4, 'e':5}
>>> series_obj = Series(dict_data_1)
>>> series_obj
a 1
b 2
c 3
d 4
e 5
dtype: int64
Dataframe 다루기 (기본)
Dataframe은 그냥 행렬이라고 생각하면 된다. Dataframe을 아예 바닥부터 만드는 방법은 다음과 같다.
>>> raw_data = {'first_name': ['Jason', 'Molly', 'Tina', 'Jake', 'Amy'],
... 'last_name': ['Miller', 'Jacobson', 'Ali', 'Milner', 'Cooze'],
... 'age': [42, 52, 36, 24, 73],
... 'city': ['San Francisco', 'Baltimore', 'Miami', 'Douglas', 'Boston']}
>>> df = pd.DataFrame(raw_data, columns = ['first_name', 'last_name', 'age', 'city'])
>>> df
first_name last_name age city
0 Jason Miller 42 San Francisco
1 Molly Jacobson 52 Baltimore
2 Tina Ali 36 Miami
3 Jake Milner 24 Douglas
4 Amy Cooze 73 Boston
열을 선택하거나 추가할 수도 있다.
>>> DataFrame(raw_data, columns = ['age', 'city'])
age city
0 42 San Francisco
1 52 Baltimore
2 36 Miami
3 24 Douglas
4 73 Boston
>>> DataFrame(raw_data, columns = ['first_name', 'last_name', 'age', 'city', 'debt'])
first_name last_name age city debt
0 Jason Miller 42 San Francisco NaN
1 Molly Jacobson 52 Baltimore NaN
2 Tina Ali 36 Miami NaN
3 Jake Milner 24 Douglas NaN
4 Amy Cooze 73 Boston NaN
새로 생긴 열은 NaN으로 지정되는 것을 확인할 수 있다.
열을 지정해서 Series로 추출해보자. 두 가지 방법이 있다.
>>> df = DataFrame(raw_data, columns = ['first_name', 'last_name', 'age', 'city', 'debt'])
>>> df.first_name
0 Jason
1 Molly
2 Tina
3 Jake
4 Amy
Name: first_name, dtype: object
>>> df['first_name']
0 Jason
1 Molly
2 Tina
3 Jake
4 Amy
Name: first_name, dtype: object
이제 좀 헷갈리는 부분이다. loc
과 iloc
의 작동 방식을 보자.
>>> df.loc[1]
first_name Molly
last_name Jacobson
age 52
city Baltimore
debt NaN
Name: 1, dtype: object
>>> df['age'].iloc[1:]
1 52
2 36
3 24
4 73
Name: age, dtype: int64
loc
은 인덱스의 이름을 받아서 반환한다. 반면, iloc
은 인덱스의 위치를 받아서 반환한다. 다음 예시를 보면 차이가 좀 더 잘 보일 것이다.
>>> import numpy as np
>>> s = pd.Series(np.nan, index=[49,48,47,46,45, 1, 2, 3, 4, 5])
>>> s
49 NaN
48 NaN
47 NaN
46 NaN
45 NaN
1 NaN
2 NaN
3 NaN
4 NaN
5 NaN
dtype: float64
>>> s.loc[:3]
49 NaN
48 NaN
47 NaN
46 NaN
45 NaN
1 NaN
2 NaN
3 NaN
dtype: float64
>>> s.iloc[:3]
49 NaN
48 NaN
47 NaN
dtype: float64
loc
을 호출하면 인덱스의 이름을 기준으로, iloc
은 인덱스의 위치를 기준으로 반환하는 것을 확인할 수 있다.
Boolean으로 열에 새로운 데이터를 할당하는 방법을 알아보자. 다음과 같은 방법은 아주 많이 사용한다.
>>> df.debt = df.age > 40
>>> df
first_name last_name age city debt
0 Jason Miller 42 San Francisco True
1 Molly Jacobson 52 Baltimore True
2 Tina Ali 36 Miami False
3 Jake Milner 24 Douglas False
4 Amy Cooze 73 Boston True
나이 열을 기준으로 해서 debt 행에 새로운 값을 부여했다.
행을 삭제할 때는 del
을 사용한다.
>>> del df['debt']
>>> df
first_name last_name age city
0 Jason Miller 42 San Francisco
1 Molly Jacobson 52 Baltimore
2 Tina Ali 36 Miami
3 Jake Milner 24 Douglas
4 Amy Cooze 73 Boston
딕셔너리를 이용해 Dataframe을 만들 수도 있다.
>>> pop = {'Nevada': {2001: 2.4, 2002: 2.9}, 'Ohio': {2000: 1.5, 2001: 1.7, 2002: 3.6}}
>>> DataFrame(pop)
Nevada Ohio
2001 2.4 1.7
2002 2.9 3.6
2000 NaN 1.5
Dataframe 다루기 (심화)
다양한 열을 선택하는 방법은 다음과 같다.
>>> df.head()
account name street city state postal-code Jan Feb Mar
0 211829 Kerluke, Koepp and Hilpert 34456 Sean Highway New Jaycob Texas 28752 10000 62000 35000
1 320563 Walter-Trantow 1311 Alvis Tunnel Port Khadijah NorthCarolina 38365 95000 45000 35000
2 648336 Bashirian, Kunde and Price 62184 Schamberger Underpass Apt. 231 New Lilianland Iowa 76517 91000 120000 35000
3 109996 DAmore, Gleichner and Bode 155 Fadel Crescent Apt. 144 Hyattburgh Maine 46021 45000 120000 10000
4 121213 Bauch-Goldner 7274 Marissa Common Shanahanchester California 49681 162000 120000 35000
>>> df[["account", "street", "state"]].head(3)
account street state
0 211829 34456 Sean Highway Texas
1 320563 1311 Alvis Tunnel NorthCarolina
2 648336 62184 Schamberger Underpass Apt. 231 Iowa
열의 이름 없이 사용하는 인덱스 숫자는 행을 기준으로 표시한다.
>>> df[:10]
account name street city state postal-code Jan Feb Mar
0 211829 Kerluke, Koepp and Hilpert 34456 Sean Highway New Jaycob Texas 28752 10000 62000 35000
1 320563 Walter-Trantow 1311 Alvis Tunnel Port Khadijah NorthCarolina 38365 95000 45000 35000
2 648336 Bashirian, Kunde and Price 62184 Schamberger Underpass Apt. 231 New Lilianland Iowa 76517 91000 120000 35000
3 109996 DAmore, Gleichner and Bode 155 Fadel Crescent Apt. 144 Hyattburgh Maine 46021 45000 120000 10000
4 121213 Bauch-Goldner 7274 Marissa Common Shanahanchester California 49681 162000 120000 35000
5 132971 Williamson, Schumm and Hettinger 89403 Casimer Spring Jeremieburgh Arkansas 62785 150000 120000 35000
6 145068 Casper LLC 340 Consuela Bridge Apt. 400 Lake Gabriellaton Mississipi 18008 62000 120000 70000
7 205217 Kovacek-Johnston 91971 Cronin Vista Suite 601 Deronville RhodeIsland 53461 145000 95000 35000
8 209744 Champlin-Morar 26739 Grant Lock Lake Juliannton Pennsylvania 64415 70000 95000 35000
9 212303 Gerhold-Maggio 366 Maggio Grove Apt. 998 North Ras Idaho 46308 70000 120000 35000
반면 열의 이름을 지정해주면 해당 열에 대해서만 추출한다.
>>> df["name"][:3]
0 Kerluke, Koepp and Hilpert
1 Walter-Trantow
2 Bashirian, Kunde and Price
Name: name, dtype: object
Series로 선택할 수도 있다. 또, 이를 이용해 Boolean으로 추출할 수도 있다.
>>> account_serires = df["account"]
>>> account_serires[:3]
0 211829
1 320563
2 648336
Name: account, dtype: int64
>>> account_serires[account_serires<250000]
0 211829
3 109996
4 121213
5 132971
6 145068
7 205217
8 209744
9 212303
10 214098
11 231907
12 242368
Name: account, dtype: int64
기본적으로 숫자로 지정된 인덱스를 변경해줄 수도 있다.
>>> df.index = df["account"]
>>> df.head()
account name street city state postal-code Jan Feb Mar
account
211829 211829 Kerluke, Koepp and Hilpert 34456 Sean Highway New Jaycob Texas 28752 10000 62000 35000
320563 320563 Walter-Trantow 1311 Alvis Tunnel Port Khadijah NorthCarolina 38365 95000 45000 35000
648336 648336 Bashirian, Kunde and Price 62184 Schamberger Underpass Apt. 231 New Lilianland Iowa 76517 91000 120000 35000
109996 109996 D'Amore, Gleichner and Bode 155 Fadel Crescent Apt. 144 Hyattburgh Maine 46021 45000 120000 10000
121213 121213 Bauch-Goldner 7274 Marissa Common Shanahanchester California 49681 162000 120000 35000
기존의 열을 제거하고 생기는 것이 아니기 때문에 del
로 제거해주면 깔끔하다.
행과 열을 이용해 데이터를 추출하는 방법은 다음과 같이 다양하다.
>>> df[["name","street"]][:2] # 열과 인덱스 숫자 이용
name street
account
211829 Kerluke, Koepp and Hilpert 34456 Sean Highway
320563 Walter-Trantow 1311 Alvis Tunnel
>>> df.loc[[211829,320563],["name","street"]] # 열의 숫자와 인덱스 숫자 이용
name street
account
211829 Kerluke, Koepp and Hilpert 34456 Sean Highway
320563 Walter-Trantow 1311 Alvis Tunnel
>>> df[["name", "street"]].iloc[:10] # 열과 인덱스 이름 이용
name street
account
211829 Kerluke, Koepp and Hilpert 34456 Sean Highway
320563 Walter-Trantow 1311 Alvis Tunnel
648336 Bashirian, Kunde and Price 62184 Schamberger Underpass Apt. 231
109996 DAmore, Gleichner and Bode 155 Fadel Crescent Apt. 144
121213 Bauch-Goldner 7274 Marissa Common
132971 Williamson, Schumm and Hettinger 89403 Casimer Spring
145068 Casper LLC 340 Consuela Bridge Apt. 400
205217 Kovacek-Johnston 91971 Cronin Vista Suite 601
209744 Champlin-Morar 26739 Grant Lock
212303 Gerhold-Maggio 366 Maggio Grove Apt. 998
인덱스를 재설정할 수도 있다.
>>> df.index = list(range(0,15))
>>> df.head()
name street city state postal-code Jan Feb Mar
0 Kerluke, Koepp and Hilpert 34456 Sean Highway New Jaycob Texas 28752 10000 62000 35000
1 Walter-Trantow 1311 Alvis Tunnel Port Khadijah NorthCarolina 38365 95000 45000 35000
2 Bashirian, Kunde and Price 62184 Schamberger Underpass Apt. 231 New Lilianland Iowa 76517 91000 120000 35000
3 D'Amore, Gleichner and Bode 155 Fadel Crescent Apt. 144 Hyattburgh Maine 46021 45000 120000 10000
4 Bauch-Goldner 7274 Marissa Common Shanahanchester California 49681 162000 120000 35000
drop
을 이용하면 행을 제거할 수 있다.
>>> df.drop(1)
name street city state postal-code Jan Feb Mar
0 Kerluke, Koepp and Hilpert 34456 Sean Highway New Jaycob Texas 28752 10000 62000 35000
2 Bashirian, Kunde and Price 62184 Schamberger Underpass Apt. 231 New Lilianland Iowa 76517 91000 120000 35000
3 DAmore, Gleichner and Bode 155 Fadel Crescent Apt. 144 Hyattburgh Maine 46021 45000 120000 10000
4 Bauch-Goldner 7274 Marissa Common Shanahanchester California 49681 162000 120000 35000
5 Williamson, Schumm and Hettinger 89403 Casimer Spring Jeremieburgh Arkansas 62785 150000 120000 35000
6 Casper LLC 340 Consuela Bridge Apt. 400 Lake Gabriellaton Mississipi 18008 62000 120000 70000
7 Kovacek-Johnston 91971 Cronin Vista Suite 601 Deronville RhodeIsland 53461 145000 95000 35000
8 Champlin-Morar 26739 Grant Lock Lake Juliannton Pennsylvania 64415 70000 95000 35000
9 Gerhold-Maggio 366 Maggio Grove Apt. 998 North Ras Idaho 46308 70000 120000 35000
10 Goodwin, Homenick and Jerde 649 Cierra Forks Apt. 078 Rosaberg Tenessee 47743 45000 120000 55000
11 Hahn-Moore 18115 Olivine Throughway Norbertomouth NorthDakota 31415 150000 10000 162000
12 Frami, Anderson and Donnelly 182 Bertie Road East Davian Iowa 72686 162000 120000 35000
13 Walsh-Haley 2624 Beatty Parkways Goodwinmouth RhodeIsland 31919 55000 120000 35000
14 McDermott PLC 8917 Bergstrom Meadow Kathryneborough Delaware 27933 150000 120000 70000
행은 물론이고 축을 지정해서 열을 제거할 수도 있다.
>>> df.drop("city",axis=1).head()
name street state postal-code Jan Feb Mar
0 Kerluke, Koepp and Hilpert 34456 Sean Highway Texas 28752 10000 62000 35000
1 Walter-Trantow 1311 Alvis Tunnel NorthCarolina 38365 95000 45000 35000
2 Bashirian, Kunde and Price 62184 Schamberger Underpass Apt. 231 Iowa 76517 91000 120000 35000
3 DAmore, Gleichner and Bode 155 Fadel Crescent Apt. 144 Maine 46021 45000 120000 10000
4 Bauch-Goldner 7274 Marissa Common California 49681 162000 120000 35000
삭제를 하더라도 기존 데이터는 변하지 않는다. 기존 데이터도 바뀌기를 원하면 inplace=True
로 설정해야 한다.
Dataframe 연산
Dataframe을 합하면 인덱스를 기준으로 연산을 하고, 겹치는 인덱스가 없으면 NaN을 반환한다.
>>> s1 = Series(range(1,6), index=list("abced"))
>>> s1
a 1
b 2
c 3
e 4
d 5
dtype: int64
>>> s2 = Series(range(5,11), index=list("bcedef"))
>>> s2
b 5
c 6
e 7
d 8
e 9
f 10
dtype: int64
>>> s1 + s2
a NaN
b 7.0
c 9.0
d 13.0
e 11.0
e 13.0
f NaN
dtype: float64
다만 다음처럼 NaN 값을 없앨 수도 있다.
>>> s1.add(s2, fill_value = 0)
a 1.0
b 7.0
c 9.0
d 13.0
e 11.0
e 13.0
f 10.0
dtype: float64
Series와 Dataframe을 합하면 broadcasting이 일어난다.
람다 함수, map, apply
판다스에서도 람다 함수, map을 사용할 수 있다. 간단한 활용 예시를 보자.
>>> s1 = Series(np.arange(10))
>>> s1.head(5)
0 0
1 1
2 2
3 3
4 4
dtype: int64
>>> s1.map(lambda x: x**2).head(5)
0 0
1 1
2 4
3 9
4 16
dtype: int64
데이터를 우리가 원하는 형식으로 변환할 때 유용하게 사용할 수 있다.
>>> z = {1: 'A', 2: 'B', 3: 'C'}
>>> s1.map(z).head(5)
0 NaN
1 A
2 B
3 C
4 NaN
dtype: object
>>> s2 = Series(np.arange(10, 20))
>>> s1.map(s2).head(5)
0 10
1 11
2 12
3 13
4 14
dtype: int64
replace
는 map
함수의 기능 중에 데이터 변환의 기능만 담당한다. 데이터 변환 시에 많이 사용한다.
apply
는 map
과 달리 series 전체에 함수를 적용한다.
applymap
은 series 단위가 아닌 요소 단위로 함수를 적용한다.
판다스 built-in 함수
대표적인 판다스 built-in 함수는 descibe
가 있다. 데이터의 요약 정보를 보여준다.
>>> df.descibe()
unique
는 series에서 유일한 값의 리스트를 반환한다.
별도의 출처 표시가 있는 이미지를 제외한 모든 이미지는 강의자료에서 발췌하였음을 밝힙니다.
댓글남기기