책 예제, 임의로 예제 만든 것 섞어서 사용합니다.
책: AICE Associate
01) 칼럼명으로 데이터 선택하기
df[['칼럼명1', '칼럼명2', ...]] # 한 개도 가능
+) df[]와 df[[]]의 차이
print(type(df[''])) # <class 'pandas.core.series.Series'>
print(type(df[['']])) # <class 'pandas.core.frame.DataFrame'>
팬시 인덱싱(Fancy Indexing)
# 데이터 프레임 팬시인덱싱
import pandas as pd
df = pd.DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6], 'c': [7, 8, 9]})
print(df[['b', 'a']])
# b a
# 0 4 1
# 1 5 2
# 2 6 3
# 넘파이 팬시인덱싱
import numpy as np
arr = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9])
arr = arr.reshape(3, 3)
print(arr[[2], 0:2]) # array([[7, 8]])
02) 행 범위를 지정하여 데이터 선택하기
특정 행 범위에서 데이터를 가져올 때 슬라이싱(Slicing)을 이용해 가져올 수 있다.
슬라이싱(Slicing)
: 연속된 데이터를 확인하는데 유용하며 인덱스와 마찬가지로 순서가 있는 자료 구조에서 사용 가능하다.
df[1:2]
# a b c
# 1 2 5 8
03) 특정 행, 열 범위를 선택해 데이터 선택하기
| loc(location) | iloc(integer location) |
|---|---|
| 데이터프레임의 행이나 열에 레이블로 접근 | 데이터프레임의 행이나 열에 인덱스값으로 접근 |
| 인덱스 및 칼럼명을 통해 지정하는 방법 | 인덱스를 활용해 지정하는 방법 |
| 설정한 인덱스를 그대로 사용 | 0 based index로 사용 |
차이를 구분하기 위해 인덱스를 재설정을 한다.
# 기존 인덱스 확인
print(df.index) # RangeIndex(start=0, stop=3, step=1)
# 인덱스 새로 지정하기
df.index = np.arrange(101, 104) # 혹은 df.index = df.index + 101
print(df.index) # RangeIndex(start=101, stop=104, step=1)
# loc: 기존 인덱스를 사용할 수 있다.
df.loc[[101, 102]]
# a b c
# 101 1 4 7
# 103 3 6 9
# iloc: 0부터 시작하는 인덱스를 사용해야한다.
df.iloc[[0, 2]]
# a b c
# 101 1 4 7
# 103 3 6 9
행과 열을 동시에 사용하는 경우 loc와 iloc
101, 103행과 a, c열 조회
# loc
df.loc[[101, 103], ['a', 'b']]
# a b
# 101 1 4
# 103 3 6
# iloc
df.iloc[[0, 2], [0, 1]]
# a b
# 101 1 4
# 103 3 6
04) 조건으로 데이터 선택하기
Boolean 연산으로 원하는 데이터만 추출 가능하다.
# 데이터 프레임 새로 생성
import pandas as pd
from random import randrange, choice
num = [i + 1 for i in range(25)]
obj = [chr(randrange(65, 70)) for _ in range(len(num))]
color = [choice(['red', 'green', 'blue']) for _ in range(len(num))]
df = pd.DataFrame({'num': num, 'obj': obj, 'color': color})
# boolean 연산으로 조건을 만족하는 데이터만 추출하기
## num가 5 미만이고, color가 red인 항목만 추출
df[(df['num'] < 5) & (df['color'] == 'red')]
# num obj color
# 1 2 B red
# 2 3 A red
조건을 한번에 전부 넣어서 사용할 수 있지만, 조건을 자주 변경해야하거나 너무 많을 경우 조건을 변수로 저장해 사용할 수 있다.
# num가 5 미만이고, color가 red인 항목만 추출
num_tag = df['num'] < 5
color_tag = df['color'] == 'red'
df[num_tag & color_tag]#.head()
# num obj color
# 1 2 B red
# 2 3 A red
01) 데이터 추가하기
# 기존 데이터프레임 컬럼을 이용해서 새 컬럼 추가
df['num2'] = df['num'] * 2 # num 칼럼 두 배한 칼럼 추가
print(df.head(3))
# num obj color num2
# 0 1 B blue 2
# 1 2 B red 4
# 2 3 A red 6
# 생성한 칼럼으로 새 컬럼 생성
df['num_sum'] = df['num'] + df['num2'] # num 칼럼 두 배한 칼럼 추가
print(df.head(3))
df['num_sum'] = df['num'] + df['num2']
print(df.head(3))
# num obj color num2 num_sum
# 0 1 B blue 2 3
# 1 2 B red 4 6
# 2 3 A red 6 9
데이터 삽입 - insert 사용
df.insert(loc, column, value, allow_deplicates=False)
# loc: 삽입될 열 위치
# column: 삽입될 열의 이름
# value: 삽입될 열의 값
# allow_duplicates: 중복 열의 삽입 허용할지 (True/False)
df.insert(5, 'num3', df['num2']*df['num_sum'])
print(df.head(3))
# num obj color num2 num_sum num3
# 0 1 B blue 2 3 6
# 1 2 B red 4 6 24
# 2 3 A red 6 9 54
02) 데이터 삭제하기
axis = 1: 열 레벨로 데이터를 삭제
axis = 0: 행 레벨로 데이터를 삭제
# 열(칼럼) 삭제 후 데이터프레임 저장
df = df.drop('num3', axis=1).head(3)
## 같은 변수명을 쓸거면 df.drop('num3', axis=1, inplace=True)을 사용해도 됨
print(df)
# num obj color num2 num_sum
# 0 1 B blue 2 3
# 1 2 B red 4 6
# 2 3 A red 6 9
# 행 삭제
print(df.drop(index=24, axis=0).tail(3))
# num obj color num2 num_sum
# 21 22 C green 44 66
# 22 23 D blue 46 69
# 23 24 A green 48 72
03) 칼럼명 변경하기
# rename 사용해서 칼럼명 변경하기
df = df.rename(columns={'num':'num1', 'obj':'level'})
print(df.head(3))
# num1 level color num2 num_sum
# 0 1 B blue 2 3
# 1 2 B red 4 6
# 2 3 A red 6 9
04) 데이터프레임 정렬하기
df.sort_values 파라미터
# num1 칼럼 기준 역순 정렬 ascending/defalt = True
df.sort_values(by='num1', ascending=False).head(3)
# num1 level color num2 num_sum
# 24 25 E blue 50 75
# 23 24 A green 48 72
# 22 23 D blue 46 69
01) 그룹화하기
(1) groupby 활용하기
그룹화 과정
- split: 그룹별로 데이터 나눈다.
- apply: 각 그룹별로 집계함수 적용한다.
- combine: 그룹별 집계 결과를 하나로 합친다.
flight = pd.read_csv(r'.\Clean_Dataset.csv', encoding='cp949')
flight.head(3)
# Unnamed: 0 airline flight source_city departure_time stops arrival_time destination_city class duration days_left price
# 0 0 SpiceJet SG-8709 Delhi Evening zero Night Mumbai Economy 2.17 1 5953
# 1 1 SpiceJet SG-8157 Delhi Early_Morning zero Morning Mumbai Economy 2.33 1 5953
# 2 2 AirAsia I5-764 Delhi Early_Morning zero Early_Morning Mumbai Economy 2.17 1 5956
airline 칼럼 기준으로 그룹화하기
airline_group = flight.groupby('airline')
print(airline_group) # <pandas.core.groupby.generic.DataFrameGroupBy object at 0x0000015D6D316EA0>
df.groupby는 데이터프레임으로 그룹까지 생성한 것이다. 그룹화된 결과를 확인하려면 .groups 속성을 사용해야한다.
print(airline_group.groups)
# {'AirAsia': [2, 18, 19, 27, 48, 141, 147, 148, 157, 265, 290, 325, 435, 450, 608, 609, 623, 706, 746, 782, 783, 784, 814, 978, 993, 1085, 1088, 1133, 1210, 1248, 1261, 1284, 1323, 1341, 1343, 1461, 1466, 1483, 1526, 1583, 1685, 1693, 1694, 1695, 1696, 1697, 1698, 1699, 1700, 1701, 1728, 1759, 1760, 1761, 1762, 1866, 1911, 1912, 1913, 1914, 1915, 1916, 1917, 1947, 1972, 1974, 1976, 1977, 1991, 1992, 2083, 2127, 2128, 2129, 2130, 2131, 2132, 2133, 2134, 2135, 2167, 2194, 2196, 2264, 2265, 2292, 2305, 2350, 2351, 2352, 2353, 2354, 2355, 2397, 2422, 2423, 2443, 2444, 2465, 2484, ...], 'Air_India': [16, 17, 23, 37, 40, 41, 42, 43, 44, 49, 50, 51, 52, 53, 60, 71, 74, 75, 82, 86, 87, 96, 98, 107, 108, 110, 113, 114, 115, 117, 142, 143, 144, 145, 146, 151, 152, 162, 163, 164, 166, 168, 173, 182, 189, 191, 193, 195, 196, 197, 198, 199, 207, 211, 223, 225, 229, 236, 237, 241, 242, 243, 247, 250, 266, 267, 268, 269, 272, 280, 291, 295, 303, 309, 314, 315, 316, 319, 321, 329, 333, 343, 352, 357, 361, 362, 363, 372, 376, 379, 380, 381, 385, 387, 388, 390, 391, 392, 393, 394, ...], 'GO_FIRST': [8, 9, 10, 11, 20, 21, 22, 30, 68, 72, 101, 112, 126, 127, 128, 129, 130, 131, 149, 150, 200, 201, 208, 212, 213, 222, 232, 235, 244, 245, 257, 258, 259, 260, 270, 271, 277, 278, 281, 296, 312, 313, 317, 327, 328, 342, 366, 368, 371, 384, 389, 413, 414, 415, 416, 417, 418, 436, 437, 438, 439, 440, 441, 442, 455, 465, 469, 490, 491, 496, 497, 535, 552, 586, 587, 588, 589, 590, 591, 610, 611, 612, 613, 614, 615, 616, 617, 627, 639, 640, 646, 668, 669, 672, 673, 675, 691, 762, 763, 764, ...], 'Indigo': [12, 13, 14, 15, 24, 26, 29, 31, 54, 55, 56, 57, 58, 67, 79, 81, 132, 133, 134, 135, 136, 137, 139, 140, 158, 159, 167, 170, 171, 172, 174, 175, 180, 181, 190, 224, 226, 228, 261, 262, 263, 264, 282, 283, 284, 285, 286, 287, 292, 297, 301, 302, 307, 308, 310, 323, 324, 332, 337, 348, 353, 354, 358, 359, 360, 419, 420, 421, 422, 424, 425, 426, 427, 428, 445, 446, 447, 451, 454, 456, 457, 458, 459, 466, 479, 488, 489, 522, 524, 592, 593, 594, 595, 596, 597, 598, 599, 600, 601, 625, ...], 'SpiceJet': [0, 1, 28, 38, 39, 45, 80, 118, 119, 138, 160, 161, 194, 227, 251, 252, 253, 274, 275, 294, 306, 311, 331, 398, 399, 400, 401, 402, 403, 423, 444, 448, 449, 452, 520, 540, 563, 564, 565, 566, 567, 568, 569, 570, 619, 620, 621, 622, 624, 665, 738, 739, 740, 741, 742, 743, 744, 745, 799, 800, 802, 844, 877, 898, 919, 920, 921, 922, 923, 924, 925, 971, 974, 975, 1049, 1092, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1150, 1155, 1200, 1243, 1281, 1286, 1287, 1288, 1289, 1290, 1291, 1331, 1332, 1368, 1369, 1412, ...], 'Vistara': [3, 4, 5, 6, 7, 25, 32, 33, 34, 35, 36, 46, 47, 59, 61, 62, 63, 64, 65, 66, 69, 70, 73, 76, 77, 78, 83, 84, 85, 88, 89, 90, 91, 92, 93, 94, 95, 97, 99, 100, 102, 103, 104, 105, 106, 109, 111, 116, 120, 121, 122, 123, 124, 125, 153, 154, 155, 156, 165, 169, 176, 177, 178, 179, 183, 184, 185, 186, 187, 188, 192, 202, 203, 204, 205, 206, 209, 210, 214, 215, 216, 217, 218, 219, 220, 221, 230, 231, 233, 234, 238, 239, 240, 246, 248, 249, 254, 255, 256, 273, ...]}
가독성이 좋지 않다.
그룹화된 결과를 groupby 메소드로 확인할 수도 있는데 확인할 수 있는 정보는 아래와 같다.
- count: 데이터 개수
- size: 집단별 크기
- sum: 데이터 합
- mean, std, var: 평균, 표준편차, 분산
- min, max: 최솟값, 최댓값
count
airline_group.count()
# Unnamed: 0 flight source_city departure_time stops arrival_time destination_city class duration days_left price
# airline
# AirAsia 16098 16098 16098 16098 16098 16098 16098 16098 16098 16098 16098
# Air_India 80892 80892 80892 80892 80892 80892 80892 80892 80892 80892 80892
# GO_FIRST 23173 23173 23173 23173 23173 23173 23173 23173 23173 23173 23173
# Indigo 43120 43120 43120 43120 43120 43120 43120 43120 43120 43120 43120
# SpiceJet 9011 9011 9011 9011 9011 9011 9011 9011 9011 9011 9011
# Vistara 127859 127859 127859 127859 127859 127859 127859 127859 127859 127859 127859
airline별 최솟값 확인
airline_group.min()
# Unnamed: 0 flight source_city departure_time stops arrival_time destination_city class duration days_left price
# airline
# AirAsia 2 I5-1228 Bangalore Afternoon one Afternoon Bangalore Economy 0.92 1 1105
# Air_India 16 AI-401 Bangalore Afternoon one Afternoon Bangalore Business 1.00 1 1526
# GO_FIRST 8 G8-101 Bangalore Afternoon one Afternoon Bangalore Economy 1.00 1 1105
# Indigo 12 6E-102 Bangalore Afternoon one Afternoon Bangalore Economy 0.83 1 1105
# SpiceJet 0 SG-1031 Bangalore Afternoon one Afternoon Bangalore Economy 1.00 1 1106
# Vistara 3 UK-613 Bangalore Afternoon one Afternoon Bangalore Business 1.00 1 1714
airline별 수치형 데이터의 평균값
airline_group.mean(numeric_only=True)
# Unnamed: 0 duration days_left price
# airline
# AirAsia 95102.971922 8.941714 27.735184 4091.072742
# Air_India 162945.107007 15.504235 25.497466 23507.019112
# GO_FIRST 87630.797005 8.755380 27.430415 5652.007595
# Indigo 110102.972658 5.795197 26.264309 5324.216303
# SpiceJet 91878.408834 12.579767 24.122850 6179.278881
# Vistara 177755.288310 13.326634 25.894532 30396.536302
# 특정 컬럼 평균
airline_group.mean(numeric_only=True)['price']
# airline
# AirAsia 4091.072742
# Air_India 23507.019112
# GO_FIRST 5652.007595
# Indigo 5324.216303
# SpiceJet 6179.278881
# Vistara 30396.536302
# Name: price, dtype: float64
여러 개 칼럼을 기준으로 groupby를 실행해다중 인덱싱을 할 수 있다.
flight.groupby(['airline', 'arrival_time']).mean(numeric_only=True)
# Unnamed: 0 duration days_left price
# airline arrival_time
# AirAsia Afternoon 88816.983918 7.496335 26.980507 4206.467836
# Early_Morning 99485.108742 9.454591 27.088842 3632.676617
# Evening 80346.891383 8.628675 27.119117 4539.570963
# Late_Night 105201.948725 9.205835 29.071899 3828.437410
# Morning 107012.537642 9.934108 27.857339 3846.900653
# Night 88657.478861 8.740391 27.487202 4320.171700
# Air_India Afternoon 162295.572046 15.954563 25.827142 23426.571700
# Early_Morning 138717.490455 17.037971 27.539501 18805.551542
# Evening 166211.387508 15.878056 24.942981 24459.593397
# Late_Night 166665.450239 13.214077 24.301435 28014.163158
# Morning 162496.968910 16.411557 25.655767 22792.180401
# Night 164175.090257 14.230348 25.451735 23683.386323
# GO_FIRST Afternoon 90534.220872 7.510892 27.706789 5511.206937
# Early_Morning 85682.954898 10.148961 27.533457 5537.433272
# Evening 86610.596935 8.284801 27.474795 6022.345547
# Late_Night 90382.433765 7.957369 29.245500 5306.723182
# Morning 84289.646143 9.633676 26.265846 5281.059399
# Night 87864.810293 9.087003 26.971360 5808.054728
여러 개 칼럼을 groupby 해서 새 데이터프레임 생성하기
flight.groupby(['airline', 'arrival_time']).mean(numeric_only=True).loc[[('AirAsia', 'Evening')]]
# Unnamed: 0 duration days_left price
# airline arrival_time
# AirAsia Evening 80346.891383 8.628675 27.119117 4539.570963
(2) 인덱스로 그룹화하기
인덱스를 설정해 그룹화할 때도 마찬가지로 groupby 메소드에 레벨(level) 설정이 가능
인덱스 관련 메소드
- set_index: 칼럼을 인덱스로 변경하는 경우 사용 기존 인덱스를 제거하고 칼럼 중 하나를 인덱스로 설정
- reset_index: 인덱스를 초기화
# set_index로 기존 칼럼 인덱스 설정하기
flight.set_index(['airline', 'arrival_time'])
# Unnamed: 0 flight source_city departure_time stops destination_city class duration days_left price
# airline arrival_time
# SpiceJet Night 0 SG-8709 Delhi Evening zero Mumbai Economy 2.17 1 5953
# Morning 1 SG-8157 Delhi Early_Morning zero Mumbai Economy 2.33 1 5953
# AirAsia Early_Morning 2 I5-764 Delhi Early_Morning zero Mumbai Economy 2.17 1 5956
# Afternoon 3 UK-995 Delhi Morning zero Mumbai Economy 2.25 1 5955
# Morning 4 UK-963 Delhi Morning zero Mumbai Economy 2.33 1 5955
# ... ... ... ... ... ... ... ... ... ... ... ...
# Vistara Evening 300148 UK-822 Chennai Morning one Hyderabad Business 10.08 49 69265
# Night 300149 UK-826 Chennai Afternoon one Hyderabad Business 10.42 49 77105
# Night 300150 UK-832 Chennai Early_Morning one Hyderabad Business 13.83 49 79099
# Evening 300151 UK-828 Chennai Early_Morning one Hyderabad Business 10.00 49 81585
# Evening 300152 UK-822 Chennai Morning one Hyderabad Business 10.08 49 81585
# 300153 rows × 10 columns
실행결과를 보면 인덱스를 설정할 뿐 그룹화를 수행한 결과가 아님을 알 수 있다.
set_index로 인덱스 설정 후 인덱스 중 하나를 기준으로 그룹화하기
# 다중 인덱스(multi-index) 세팅 후 해당 인덱스 기준으로 groupby하기
flight.set_index(['airline', 'arrival_time']).groupby(level=[0]).mean(numeric_only=True)
# Unnamed: 0 duration days_left price
# airline
# AirAsia 95102.971922 8.941714 27.735184 4091.072742
# Air_India 162945.107007 15.504235 25.497466 23507.019112
# GO_FIRST 87630.797005 8.755380 27.430415 5652.007595
# Indigo 110102.972658 5.795197 26.264309 5324.216303
# SpiceJet 91878.408834 12.579767 24.122850 6179.278881
# Vistara 177755.288310 13.326634 25.894532 30396.536302
airline_group.mean(numeric_only=True)과 비교해 보면 동일한 데이터를 설정했고, 레벨(depth)를 0으로 설정한 인덱스 중 airline을 기준으로 그룹화한 것을 확인할 수 있다.
# 인덱스를 모두 선택해 groupby 실행
flight.set_index(['airline', 'arrival_time']).groupby(level=[0, 1]).mean(numeric_only=True)
# Unnamed: 0 duration days_left price
# airline arrival_time
# AirAsia Afternoon 88816.983918 7.496335 26.980507 4206.467836
# Early_Morning 99485.108742 9.454591 27.088842 3632.676617
# Evening 80346.891383 8.628675 27.119117 4539.570963
# Late_Night 105201.948725 9.205835 29.071899 3828.437410
# Morning 107012.537642 9.934108 27.857339 3846.900653
# Night 88657.478861 8.740391 27.487202 4320.171700
# Air_India Afternoon 162295.572046 15.954563 25.827142 23426.571700
# Early_Morning 138717.490455 17.037971 27.539501 18805.551542
# Evening 166211.387508 15.878056 24.942981 24459.593397
# Late_Night 166665.450239 13.214077 24.301435 28014.163158
# Morning 162496.968910 16.411557 25.655767 22792.180401
# Night 164175.090257 14.230348 25.451735 23683.386323
# GO_FIRST Afternoon 90534.220872 7.510892 27.706789 5511.206937
# ... ... ... ... ...
(3) Aggregate로 집계하기
aggregate로 데이터프레임 값을 다양하게 집계해 한 번에 확인할 수 있다.
numeric = flight.select_dtypes(include='number').columns
flight.set_index(['airline', 'arrival_time'])[numeric].groupby(level=[0, 1]).aggregate(['mean', 'max'])
# Unnamed: 0 duration days_left price
# mean max mean max mean max mean max
# airline arrival_time
# AirAsia Afternoon 88816.983918 202598 7.496335 18.33 26.980507 49 4206.467836 31917
# Early_Morning 99485.108742 193744 9.454591 15.50 27.088842 49 3632.676617 29501
# Evening 80346.891383 205846 8.628675 14.58 27.119117 49 4539.570963 31799
# Late_Night 105201.948725 202571 9.205835 17.33 29.071899 49 3828.437410 31707
# Morning 107012.537642 206617 9.934108 19.58 27.857339 49 3846.900653 26360
# Night 88657.478861 202569 8.740391 18.00 27.487202 49 4320.171700 30211
# Air_India Afternoon 162295.572046 299989 15.954563 44.50 25.827142 49 23426.571700 86491
# Early_Morning 138717.490455 300114 17.037971 40.75 27.539501 49 18805.551542 80762
# Evening 166211.387508 299935 15.878056 49.83 24.942981 49 24459.593397 84374
# Late_Night 166665.450239 295659 13.214077 41.58 24.301435 49 28014.163158 89257
# Morning 162496.968910 300146 16.411557 45.83 25.655767 49 22792.180401 86491
# Night 164175.090257 300147 14.230348 41.83 25.451735 49 23683.386323 90970
# GO_FIRST Afternoon 90534.220872 206589 7.510892 17.92 27.706789 49 5511.206937 31773
# Early_Morning 85682.954898 202069 10.148961 22.50 27.533457 49 5537.433272 25462
# Evening 86610.596935 206183 8.284801 15.50 27.474795 49 6022.345547 28174
# Late_Night 90382.433765 197767 7.957369 16.08 29.245500 49 5306.723182 16120
# Morning 84289.646143 187519 9.633676 20.67 26.265846 49 5281.059399 27620
# Night 87864.810293 206320 9.087003 17.00 26.971360 49 5808.054728 32803
# ... ... ... ... ... ... ... ... ...
02) 피벗테이블 생성하기
'(축을 중심으로) 회전한다.'는 사전적 의미처럼 pivot과 pivot_tabel 메소드는 행 데이터를 열 데이터로 회전할 수 있다.
# 테이블 생성
pivot_data = pd.DataFrame({'cust_id':['cust_1', 'cust_1', 'cust_1', 'cust_2', 'cust_2', 'cust_2', 'cust_3', 'cust_3', 'cust_3'], 'prod_cd':['p1', 'p2', 'p3', 'p1', 'p2', 'p3', 'p1', 'p2', 'p3'], 'grade':['A', 'A', 'A', 'A', 'A', 'A', 'B', 'B', 'B'], 'purch_amt':[30, 10, 0, 40, 15, 30, 0, 0, 10]})
pivot_data
# cust_id prod_cd grade purch_amt
# 0 cust_1 p1 A 30
# 1 cust_1 p2 A 10
# 2 cust_1 p3 A 0
# 3 cust_2 p1 A 40
# 4 cust_2 p2 A 15
# 5 cust_2 p3 A 30
# 6 cust_3 p1 B 0
# 7 cust_3 p2 B 0
# 8 cust_3 p3 B 10
# 데이터 변경하기_pivot
pivot_data.pivot(index='cust_id', columns='prod_cd', values='purch_amt')
# prod_cd p1 p2 p3
# cust_id
# cust_1 30 10 0
# cust_2 40 15 30
# cust_3 0 0 10
# index와 colums, values를 지정하지 않을 경우 차례대로 index, colums, values으로 인식한다.
pivot_data.pivot('cust_id','prod_cd', 'purch_amt')
pivot_table은 pivot과 기능은 동일하지만, pivot와 달리 aggfunc를 지정할 수 있다.
중복값이 있을 경우 pivot은 사용할 수 없지만, pivot_table은 쓸 수 있다.
pivot_data.pivot_table(index='grade', columns='prod_cd', values='purch_amt')
# prod_cd p1 p2 p3
# grade
# A 35.0 12.5 15.0
# B 0.0 0.0 10.0
# pivot_table aggfunc 합계로 지정
pivot_data.pivot_table(index='grade', columns='prod_cd', values='purch_amt', aggfunc='sum')
# prod_cd p1 p2 p3
# grade
# A 70 25 30
# B 0 0 10
03) 인덱스 및 칼럼 라벨 변경하기
stack과 unstack
- stack: 칼럼 레벨에서 인덱스 레벨로 데이터프레임 변경 // 데이터를 행의 레벨로 쌓아올린다.
- unstack: 인덱스 레벨에서 칼럼 레벨로 위치를 변경하여 데이터를 쌓아 올린다.
# 데이터프레임 생성
stack_data = pd.DataFrame({'Location':['Seoul', 'Seoul', 'Seoul', 'kyoungggi', 'kyoungggi', 'Busan', 'Seoul', 'Seoul', 'Busan', 'kyoungggi', 'kyoungggi', 'kyoungggi'],
'Day':['Mon', 'Tue', 'Wed', 'Mon', 'Tue', 'Mon', 'Thu', 'Fri', 'Tue', 'Wed', 'Thu', 'Fri'],
'Rainfall':[100, 80, 1000, 200, 200, 100, 50, 100, 200, 100, 50, 100],
'Rainfall_precipitation':[80, 70, 90, 10, 20, 30, 50, 90, 20, 80, 50, 10],
'Temp':[32, 27, 32, 31, 30, 28, 27, 25, 26, 33, 34, 31]})
print(stack_data.head(3))
# Location Day Rainfall Rainfall_precipitation Temp
# 0 Seoul Mon 100 80 32
# 1 Seoul Tue 80 70 27
# 2 Seoul Wed 1000 90 32
# Location과 Day를 인덱스로 설정하고 새로운 데이터프레임 생성
new_stack_data = stack_data.set_index(['Location', 'Day'])
print(new_stack_data)
# Rainfall Rainfall_precipitation Temp
# Location Day
# Seoul Mon 100 80 32
# Tue 80 70 27
# Wed 1000 90 32
# kyoungggi Mon 200 10 31
# Tue 200 20 30
# Busan Mon 100 30 28
# Seoul Thu 50 50 27
# Fri 100 90 25
# Busan Tue 200 20 26
# kyoungggi Wed 100 80 33
# Thu 50 50 34
# Fri 100 10 31
unstack은 인덱스 레벨에서 칼럼 레벨로 위치를 변경하여 데이터를 쌓아올리는 것이다
new_stack_data.unstack(0)
# Rainfall Rainfall_precipitation Temp
# Location Busan Seoul kyoungggi Busan Seoul kyoungggi Busan Seoul kyoungggi
# Day
# Fri NaN 100.0 100.0 NaN 90.0 10.0 NaN 25.0 31.0
# Mon 100.0 100.0 200.0 30.0 80.0 10.0 28.0 32.0 31.0
# Thu NaN 50.0 50.0 NaN 50.0 50.0 NaN 27.0 34.0
# Tue 200.0 80.0 200.0 20.0 70.0 20.0 26.0 27.0 30.0
# Wed NaN 1000.0 100.0 NaN 90.0 80.0 NaN 32.0 33.0
unstack(0)을 실행해보면, 첫 번째 인덱스 Location이 칼럼 레벨로 올라갔고 기존 칼럼인 'Rainfall', 'Rainfall_precipitation', 'Temp' 밑에 Location이 있으며 Location 별로 데이터를 확인할 수 있다.
new_stack_data.unstack(1)
# Rainfall Rainfall_precipitation Temp
# Day Fri Mon Thu Tue Wed Fri Mon Thu Tue Wed Fri Mon Thu Tue Wed
# Location
# Busan NaN 100.0 NaN 200.0 NaN NaN 30.0 NaN 20.0 NaN NaN 28.0 NaN 26.0 NaN
# Seoul 100.0 100.0 50.0 80.0 1000.0 90.0 80.0 50.0 70.0 90.0 25.0 32.0 27.0 27.0 32.0
# kyoungggi 100.0 200.0 50.0 200.0 100.0 10.0 10.0 50.0 20.0 80.0 31.0 31.0 34.0 30.0 33.0
unstack(1)을 실행해보면, 두 번째 인덱스였던 요일이 칼럼 레벨로 올라가있다.
stack은 칼럼 레벨에서 인덱스 레벨로 데이터프레임을 변경하는 것이다.
new_stack_data2 = new_stack_data.unstack(1)
new_stack_data2.stack(1, future_stack=True)
# Rainfall Rainfall_precipitation Temp
# Location Day
# Busan Fri NaN NaN NaN
# Mon 100.0 30.0 28.0
# Thu NaN NaN NaN
# Tue 200.0 20.0 26.0
# Wed NaN NaN NaN
# Seoul Fri 100.0 90.0 25.0
# Mon 100.0 80.0 32.0
두 번째 칼럼 레벨에 있던 day가 다시 인덱스 레벨로 변경됐음을 확인할 수 있다.
01) concat 활용하여 병합하기
concat()은 2개 이상의 데이터 프레임을 병합할 때 사용한다.
(1) 칼럼명이 같은 경우
df1 = pd.DataFrame({'col1':['사과', '배', '감', '수박', '멜론'],
'col2':[500, 1000, 2500, 5000, 3000]}, index=[0, 1, 2, 3, 4])
df2 = pd.DataFrame({'col1':['수박', '멜론', '딸기', '키위', '오렌지'],
'col2':[5000, 3000, 1000, 600, 700]}, index=[3, 4, 5, 6, 7])
pd.concat([df1, df2], ignore_index=False)
# col1 col2
# 0 사과 500
# 1 배 1000
# 2 감 2500
# 3 수박 5000
# 4 멜론 3000
# 3 수박 5000
# 4 멜론 3000
# 5 딸기 1000
# 6 키위 600
# 7 오렌지 700
ignore_index=False 일 경우, 데이터프레임이 합쳐질 때 기존 인덱스가 유지된다.
True의 경우, 새 인덱스가 부여된다.
pd.concat([df1, df2], ignore_index=True)
# col1 col2
# 0 사과 500
# 1 배 1000
# 2 감 2500
# 3 수박 5000
# 4 멜론 3000
# 5 수박 5000
# 6 멜론 3000
# 7 딸기 1000
# 8 키위 600
# 9 오렌지 700
axis를 지정하면 행 레벨로 지정할지 열 레벨로 병합할지 정의할 수 있다.
- axis=0 행 레벨로 병합 (위+아래(세로)로 합치기) // default
- axis=1 열 레벨로 병합(왼쪽+오른쪽(가로)으로 합치기)
pd.concat([df1, df2], axis=1)
# col1 col2 col1 col2
# 0 사과 500.0 NaN NaN
# 1 배 1000.0 NaN NaN
# 2 감 2500.0 NaN NaN
# 3 수박 5000.0 수박 5000.0
# 4 멜론 3000.0 멜론 3000.0
# 5 NaN NaN 딸기 1000.0
# 6 NaN NaN 키위 600.0
# 7 NaN NaN 오렌지 700.0
칼럼명이 나란히 각각 쓰여 있고, 동일한 인덱스의 경우 나란히 합쳐지고 서로 다른 인덱스의 경우 NaN과 함께 각각 출력된다.
(2) 칼럼명이 다른 경우
concat()의 파라미터인 join으로 테이블을 병합할 수 있다.
join 값
- outer: 합집합 방식
- inner: 교집합 방식
# 데이터 프레임 생성
df3 = pd.DataFrame({'item':['item0', 'item1', 'item2', 'item3'],
'count':['count0', 'count1', 'count2', 'count3'],
'price':['price0', 'price1', 'price2', 'price3']}, index=[0,1,2,3])
df4 = pd.DataFrame({'item':['item2', 'item3', 'item4', 'item5'],
'count':['count2', 'count3', 'count4', 'count5'],
'price':['price2', 'price3', 'price4', 'price5'],
'var':['var2', 'var3', 'var4', 'var5']}, index=[2,3,4,5])
# join=outer
pd.concat([df3, df4], join='outer')
# item count price var
# 0 item0 count0 price0 NaN
# 1 item1 count1 price1 NaN
# 2 item2 count2 price2 NaN
# 3 item3 count3 price3 NaN
# 2 item2 count2 price2 var2
# 3 item3 count3 price3 var3
# 4 item4 count4 price4 var4
# 5 item5 count5 price5 var5
# join=inner
pd.concat([df3, df4], join='inner')
# item count price
# 0 item0 count0 price0
# 1 item1 count1 price1
# 2 item2 count2 price2
# 3 item3 count3 price3
# 2 item2 count2 price2
# 3 item3 count3 price3
# 4 item4 count4 price4
# 5 item5 count5 price5
(3) 인덱스가 중복인 경우
concat()의 verify_intergrity 속성을 사용한다.
True인 경우 중복 오류 메시지가 뜨고, False는 에러 메시지가 뜨지 않는다. False가 default이다.
df5 = pd.DataFrame({'A':['A0', 'A1', 'A3'], 'B':['B0', 'B1', 'B3'], 'C':['C0', 'C1', 'C3'], 'D':['D0', 'D1', 'D3']}, index=['I0','I1','I2'])
df6 = pd.DataFrame({'A':['AA2', 'A3', 'A4'], 'B':['BB2', 'B3', 'B4'], 'C':['CC2', 'C3', 'C4'], 'D':['DD2', 'D3', 'D4']}, index=['I2','I3','I4'])
pd.concat([df5, df6], verify_integrity=True) # ValueError: Indexes have overlapping values: Index(['I2'], dtype='object')
2) merge/join 활용하여 병합하기
merge와 join함수로 특정 key를 기준으로 데이터 프레임을 병합할 수 있다.
# how 로 정의할 수 있는 merge 방식
- inner: 일치하는 값이 있을 때만 가져온다. // default
- left: 왼쪽 데이터프레임을 기준으로 오른쪽 데이터프레임을 병합(오른쪽 데이터프레임에 값이 없으면 NaN)
- right: 오른쪽 데이터프레임을 기준으로 왼쪽 데이터프레임 병합
- outer: left와 right를 합한 데이터프레임 병합# customer_id 기준 병합
customer = pd.DataFrame({'customer_id':np.arange(6),
'name':['James', 'Elly', 'Tom', 'Givert', 'Aiden', 'Brody'],
'나이':[40, 20, 21, 30, 31, 18]})
orders = pd.DataFrame({'customer_id':[1, 1, 2, 2, 2, 3, 3, 1, 4, 9],
'item':['마우스', '충전기', '이어폰', '헤드셋', '전자펜', '키보드', '전자펜', '마우스', '키보드', '케이스'],
'quantity':[1, 2, 1, 1, 3, 2, 2, 3, 2, 1]})
## how=inner
pd.merge(customer, orders, on='customer_id')
# = pd.merge(customer, orders, on='customer_id', how='inner')
# customer_id name 나이 item quantity
# 0 1 Elly 20 마우스 1
# 1 1 Elly 20 충전기 2
# 2 1 Elly 20 마우스 3
# 3 2 Tom 21 이어폰 1
# 4 2 Tom 21 헤드셋 1
# 5 2 Tom 21 전자펜 3
# 6 3 Givert 30 키보드 2
# 7 3 Givert 30 전자펜 2
# 8 4 Aiden 31 키보드 2
# how=left
pd.merge(customer, orders, on='customer_id', how='left')
# customer_id name 나이 item quantity
# 0 0 James 40 NaN NaN
# 1 1 Elly 20 마우스 1.0
# 2 1 Elly 20 충전기 2.0
# 3 1 Elly 20 마우스 3.0
# 4 2 Tom 21 이어폰 1.0
# 5 2 Tom 21 헤드셋 1.0
# 6 2 Tom 21 전자펜 3.0
# 7 3 Givert 30 키보드 2.0
# 8 3 Givert 30 전자펜 2.0
# 9 4 Aiden 31 키보드 2.0
# 10 5 Brody 18 NaN NaN
왼쪽 데이터프레임(customer)에는 값이 있지만 오른쪽 프레임(orders)에 값이 없는 건 NaN으로 채워져 병합된다.
right는 반대로 오른쪽 프레임에 값이 있지만 왼쪽에 없는 값이 NaN으로 표시된다.
# how=outer
pd.merge(customer, orders, on='customer_id', how='outer')
# customer_id name 나이 item quantity
# 0 0 James 40.0 NaN NaN
# 1 1 Elly 20.0 마우스 1.0
# 2 1 Elly 20.0 충전기 2.0
# 3 1 Elly 20.0 마우스 3.0
# 4 2 Tom 21.0 이어폰 1.0
# 5 2 Tom 21.0 헤드셋 1.0
# 6 2 Tom 21.0 전자펜 3.0
# 7 3 Givert 30.0 키보드 2.0
# 8 3 Givert 30.0 전자펜 2.0
# 9 4 Aiden 31.0 키보드 2.0
# 10 5 Brody 18.0 NaN NaN
# 11 9 NaN NaN 케이스 1.0
outer의 경우 'customer_id'를 모두 활용해 병합한 결과를 보여준다.
# 인덱스를 지정해 데이터프레임 합치기
cust1 = customer.set_index('customer_id')
order1 = orders.set_index('customer_id')
pd.merge(cust1, order1, left_index=True, right_index=True)
# name 나이 item quantity
# customer_id
# 1 Elly 20 마우스 1
# 1 Elly 20 충전기 2
# 1 Elly 20 마우스 3
# 2 Tom 21 이어폰 1
# 2 Tom 21 헤드셋 1
# 2 Tom 21 전자펜 3
# 3 Givert 30 키보드 2
# 3 Givert 30 전자펜 2
# 4 Aiden 31 키보드 2
customer_id를 인덱스로 설정한 두 데이터프레임을 merge하는 경우 on 파라미터를 사용하지 않고 'left_index'와 'right_index' 파라미터를 True로 지정해 두 인덱스 사이를 포함하는 'inner' 형태로 두 데이터프레임을 병합할 수 있다.