그룹화하기
groupby 메소드는 데이터프레임의 같은 값을 하나로 묶어서 통계나 집계 결과를 확안하기 위해 사용한다. 예를 들어 기상 데이터를 날짜별, 도시별로 값을 묶어서 통계나 집계 결과를 확인할 수 있다.
- Split: 그룹별로 데이터를 나눈다.
- Apply: 각 그룹별로 집계 함수를 적용한다.
- Combine: 그룹별 집계 결과를 하나로 합치는 과정이다.
import numpy as np
import pandas as pd
flight = pd.read_csv('Clean_Dataset.csv')# aireline 칼럼 기준으로 그룹화하기
airline_group = flight.groupby('airline')
airline_group<pandas.api.typing.DataFrameGroupBy object at 0x0000010EE82BBCB0>
그룹화를 수행하면 airline 기준으로 데이터들이 모일 것이라고 생각하지만, 수행한 결과는 데이터프레임으로 그룹까지 생성한 것이다.
따라서 그룹화된 결과를 확인하려면 groups 속성을 이용한다.
# 수행 결과 확인하기
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 : 최솟값, 최댓값
# 데이터 수 확인하기
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 |
데이터프레임의 복수 개의 칼럼을 기준으로 groupby를 활용하면 다중 인덱싱(multi-indexing)을 설정할 수 있다.
# groupby를 활용하여 다중 인덱싱(multi-indexing) 설정하기
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 | |
| Indigo | Afternoon | 106570.254921 | 5.483550 | 26.018053 | 5458.553278 |
| Early_Morning | 116218.737879 | 5.913914 | 29.270398 | 4107.122586 | |
| Evening | 113633.002071 | 6.255353 | 25.200587 | 5914.292555 | |
| Late_Night | 110790.778003 | 5.652350 | 27.798553 | 4989.383792 | |
| Morning | 93504.652953 | 4.389309 | 26.835436 | 4558.313037 | |
| Night | 114668.999528 | 6.176535 | 26.114164 | 5371.779781 | |
| SpiceJet | Afternoon | 96337.994076 | 14.371315 | 25.279621 | 7116.303318 |
| Early_Morning | 86212.106796 | 13.395576 | 20.773925 | 5348.022191 | |
| Evening | 97825.642908 | 13.826714 | 24.349964 | 7465.200285 | |
| Late_Night | 125755.550439 | 7.612829 | 23.339912 | 5911.436404 | |
| Morning | 88454.211881 | 12.866352 | 24.699010 | 5777.899010 | |
| Night | 87037.019268 | 11.825869 | 24.129980 | 5898.403658 | |
| Vistara | Afternoon | 176534.776824 | 12.114402 | 25.469405 | 27905.873134 |
| Early_Morning | 178997.086816 | 15.122223 | 26.597803 | 28597.738475 | |
| Evening | 178147.125191 | 13.679788 | 25.935980 | 31225.269687 | |
| Late_Night | 195942.545350 | 10.051710 | 26.937031 | 29699.180243 | |
| Morning | 177197.110088 | 14.913937 | 25.788161 | 30180.664694 | |
| Night | 177240.740619 | 12.191358 | 25.939596 | 30773.372570 |
여러 개의 칼럼을 기준으로 groupby한 경우 loc을 이용하여 원하는 인덱스의 데이터만 가져올 수 있다.
# 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 |
인덱스로 그룹화하기
인덱스를 설정하여 그룹화할 때도 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 |
| Vistara | 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 | |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | |
| 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
Aggregate로 집계하기
aggregate 메소드를 활용하면 데이터프레임의 값을 다양하게 집계하여 한 번에 볼 수 있다.
# aggregate 메소드 이용하여 groupby 후 평균값과 최댓값 확인하기
flight.set_index(['airline', 'arrival_time']).groupby(level=[0,1]).aggregate([np.min, np.max])| Unnamed: 0 | flight | source_city | departure_time | stops | destination_city | class | duration | days_left | price | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| min | max | min | max | min | max | min | max | min | max | min | max | min | max | min | max | min | max | min | max | ||
| airline | arrival_time | ||||||||||||||||||||
| AirAsia | Afternoon | 27 | 202598 | I5-1228 | I5-942 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 0.92 | 18.33 | 1 | 49 | 1443 | 31917 |
| Early_Morning | 2 | 193744 | I5-1229 | I5-996 | Bangalore | Mumbai | Early_Morning | Night | one | zero | Chennai | Mumbai | Economy | Economy | 0.92 | 15.50 | 1 | 49 | 1603 | 29501 | |
| Evening | 10006 | 205846 | I5-1228 | I5-991 | Bangalore | Mumbai | Afternoon | Morning | one | zero | Bangalore | Mumbai | Economy | Economy | 0.92 | 14.58 | 1 | 49 | 1443 | 31799 | |
| Late_Night | 1693 | 202571 | I5-1228 | I5-992 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 1.25 | 17.33 | 1 | 49 | 1443 | 31707 | |
| Morning | 19 | 206617 | I5-1228 | I5-992 | Bangalore | Mumbai | Early_Morning | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 1.00 | 19.58 | 1 | 49 | 1105 | 26360 | |
| Night | 1323 | 202569 | I5-1228 | I5-996 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 0.92 | 18.00 | 1 | 49 | 1443 | 30211 | |
| Air_India | Afternoon | 37 | 299989 | AI-402 | AI-9937 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Business | Economy | 1.00 | 44.50 | 1 | 49 | 1830 | 86491 |
| Early_Morning | 8846 | 300114 | AI-403 | AI-9928 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Business | Economy | 1.33 | 40.75 | 1 | 49 | 1776 | 80762 | |
| Evening | 110 | 299935 | AI-401 | AI-9929 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Business | Economy | 1.50 | 49.83 | 1 | 49 | 1830 | 84374 | |
| Late_Night | 193 | 295659 | AI-401 | AI-9929 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Business | Economy | 2.58 | 41.58 | 1 | 49 | 3863 | 89257 | |
| Morning | 16 | 300146 | AI-401 | AI-9929 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Business | Economy | 1.08 | 45.83 | 1 | 49 | 1526 | 86491 | |
| Night | 23 | 300147 | AI-401 | AI-9991 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Business | Economy | 1.17 | 41.83 | 1 | 49 | 1830 | 90970 | |
| GO_FIRST | Afternoon | 11 | 206589 | G8-101 | G8-917 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 1.00 | 17.92 | 1 | 49 | 1105 | 31773 |
| Early_Morning | 150 | 202069 | G8-101 | G8-815 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 1.00 | 22.50 | 1 | 49 | 1776 | 25462 | |
| Evening | 9 | 206183 | G8-101 | G8-917 | Bangalore | Mumbai | Afternoon | Morning | one | zero | Bangalore | Mumbai | Economy | Economy | 1.17 | 15.50 | 1 | 49 | 1105 | 28174 | |
| Late_Night | 1521 | 197767 | G8-102 | G8-962 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 1.25 | 16.08 | 1 | 49 | 1714 | 16120 | |
| Morning | 8 | 187519 | G8-101 | G8-812 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 1.00 | 20.67 | 1 | 49 | 1714 | 27620 | |
| Night | 21 | 206320 | G8-101 | G8-917 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 1.08 | 17.00 | 1 | 49 | 1714 | 32803 | |
| Indigo | Afternoon | 13 | 206650 | 6E-113 | 6E-982 | Bangalore | Mumbai | Afternoon | Morning | one | zero | Bangalore | Mumbai | Economy | Economy | 0.92 | 10.92 | 1 | 49 | 1105 | 29213 |
| Early_Morning | 1678 | 206607 | 6E-134 | 6E-987 | Bangalore | Mumbai | Early_Morning | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 0.83 | 12.42 | 1 | 49 | 1105 | 24120 | |
| Evening | 14 | 206614 | 6E-102 | 6E-982 | Bangalore | Mumbai | Afternoon | Morning | one | zero | Bangalore | Mumbai | Economy | Economy | 0.92 | 12.67 | 1 | 49 | 1105 | 30786 | |
| Late_Night | 772 | 206602 | 6E-126 | 6E-992 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 1.17 | 12.33 | 1 | 49 | 1105 | 25086 | |
| Morning | 12 | 206610 | 6E-121 | 6E-995 | Bangalore | Mumbai | Early_Morning | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 0.83 | 12.50 | 1 | 49 | 1105 | 24047 | |
| Night | 29 | 206615 | 6E-102 | 6E-998 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 0.83 | 15.42 | 1 | 49 | 1105 | 31952 | |
| SpiceJet | Afternoon | 45 | 193244 | SG-163 | SG-9974 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 1.25 | 26.33 | 1 | 49 | 1566 | 20874 |
| Early_Morning | 275 | 206184 | SG-1031 | SG-8803 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 1.00 | 26.33 | 1 | 44 | 1106 | 25454 | |
| Evening | 194 | 203920 | SG-197 | SG-9911 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 1.08 | 27.92 | 1 | 49 | 2491 | 27769 | |
| Late_Night | 10389 | 187402 | SG-1057 | SG-8906 | Bangalore | Kolkata | Afternoon | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 2.50 | 19.25 | 1 | 49 | 2568 | 20298 | |
| Morning | 1 | 203820 | SG-1032 | SG-9923 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 1.00 | 27.50 | 1 | 49 | 1444 | 34158 | |
| Night | 0 | 202067 | SG-1062 | SG-958 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Economy | Economy | 1.75 | 27.58 | 1 | 49 | 2100 | 26939 | |
| Vistara | Afternoon | 3 | 300133 | UK-613 | UK-996 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Business | Economy | 1.50 | 33.08 | 1 | 49 | 2022 | 115211 |
| Early_Morning | 573 | 300125 | UK-637 | UK-995 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Business | Economy | 1.50 | 26.08 | 4 | 49 | 2074 | 106416 | |
| Evening | 7 | 300152 | UK-613 | UK-996 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Business | Economy | 1.00 | 37.58 | 1 | 49 | 1776 | 117307 | |
| Late_Night | 43306 | 290332 | UK-772 | UK-986 | Bangalore | Mumbai | Afternoon | Night | one | zero | Delhi | Delhi | Business | Economy | 2.17 | 28.33 | 3 | 49 | 2339 | 83087 | |
| Morning | 4 | 300138 | UK-613 | UK-996 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Business | Economy | 1.17 | 47.08 | 1 | 49 | 1714 | 111964 | |
| Night | 46 | 300150 | UK-613 | UK-996 | Bangalore | Mumbai | Afternoon | Night | one | zero | Bangalore | Mumbai | Business | Economy | 1.00 | 40.00 | 1 | 49 | 1714 | 123071 | |
피벗 테이블 생성하기
‘(축을 중심으로) 회전한다’는 사전적 의미처럼 pivot과 pivot_table 메소드는 행 데이터를 열 데이터로 회전할 수 있다.
# pivot/pivot_table을 위한 데이터프레임 만들기
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은 기본적으로 index, columns, values를 지정하여 구성할 수 있다.
# 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 |
pivot과 pivot_table의 기능은 동일하지만, pivot_table은 pivot과 다르게 aggfunc를 지정할 수 있다. aggfunc을 지정할 때 중복값이 존재하는 경우 pivot은 사용할 수 없고 pivot_table만 사용할 수 있다.
try:
pivot_data.pivot(index='grade', columns='prod_cd', values='purch_amt')
except Exception as e:
print(f"Error occurred: {e}")Error occurred: Index contains duplicate entries, cannot reshape
pivot을 수행하면 위와 같이 인덱스에 중복이 있어 변경할 수 없다는 에러 메시지가 나타난다. 실제 인덱스로 쓰인 grade는 중복값을 가지고 있다. 하지만 pivot_table을 동일하게 수행할 경우 평균값이 결과로 보여진다.
# 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의 기본은 평균값이고, 따로 지정할 수도 있다.
아래는 aggfunc을 합계로 지정한 예시이다.
# pivot_table의 aggfunc 지정하기
pivot_data.pivot_table(index='grade', columns='prod_cd', values='purch_amt', aggfunc=np.sum)| prod_cd | p1 | p2 | p3 |
|---|---|---|---|
| grade | |||
| A | 70 | 25 | 30 |
| B | 0 | 0 | 10 |
인덱스 및 칼럼 레벨 변경하기
데이터프레임을 변형하는 또 다른 방법으로 stack/unstack 메소드를 알아보자. ‘쌓다’라는 의미로 stack은 칼럼 레벨에서 인덱스 레벨로 데이터프레임을 변경한다. 데이터를 행의 레벨로 쌓아 올리는 개념으로 이해하면 된다.
반대로 unstack은 인덱스 레벨에서 칼럼 레벨로 위치를 변경하여 데이터를 쌓아 올린다.
# stack/unstack을 위한 데이터프레임 만들기
stack_data = pd.DataFrame({
'Location': ['Seoul', 'Seoul', 'Seoul', 'Kyounggi', 'Kyounggi', 'Busan', 'Seoul', 'Seoul', 'Busan', 'Kyounggi', 'Kyounggi', 'Kyounggi'],
'Day': ['Mon', 'Tue', 'Wed', 'Mon', 'Tue', 'Mon', 'Thu', 'Fri', 'Tue', 'Wed', 'Thu', 'Fri'],
'Ranfall': [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]
})
stack_data| Location | Day | Ranfall | Rainfall_precipitation | Temp | |
|---|---|---|---|---|---|
| 0 | Seoul | Mon | 100 | 80 | 32 |
| 1 | Seoul | Tue | 80 | 70 | 27 |
| 2 | Seoul | Wed | 1000 | 90 | 32 |
| 3 | Kyounggi | Mon | 200 | 10 | 31 |
| 4 | Kyounggi | Tue | 200 | 20 | 30 |
| 5 | Busan | Mon | 100 | 30 | 28 |
| 6 | Seoul | Thu | 50 | 50 | 27 |
| 7 | Seoul | Fri | 100 | 90 | 25 |
| 8 | Busan | Tue | 200 | 20 | 26 |
| 9 | Kyounggi | Wed | 100 | 80 | 33 |
| 10 | Kyounggi | Thu | 50 | 50 | 34 |
| 11 | Kyounggi | Fri | 100 | 10 | 31 |
Location과 Day를 인덱스로 설정하고 새로운 데이터프레임을 만든다.
# 인덱스 설정하기
new_stack_data = stack_data.set_index(['Location', 'Day'])
new_stack_data| Ranfall | Rainfall_precipitation | Temp | ||
|---|---|---|---|---|
| Location | Day | |||
| Seoul | Mon | 100 | 80 | 32 |
| Tue | 80 | 70 | 27 | |
| Wed | 1000 | 90 | 32 | |
| Kyounggi | 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 |
| Kyounggi | Wed | 100 | 80 | 33 |
| Thu | 50 | 50 | 34 | |
| Fri | 100 | 10 | 31 |
unstack은 인덱스 레벨에서 칼럼 레벨로 위치를 변경하여 데이터를 쌓아 올리는 것이다.
# unstack 확인하기
new_stack_data.unstack(0)| Ranfall | Rainfall_precipitation | Temp | |||||||
|---|---|---|---|---|---|---|---|---|---|
| Location | Busan | Kyounggi | Seoul | Busan | Kyounggi | Seoul | Busan | Kyounggi | Seoul |
| Day | |||||||||
| Fri | NaN | 100.0 | 100.0 | NaN | 10.0 | 90.0 | NaN | 31.0 | 25.0 |
| Mon | 100.0 | 200.0 | 100.0 | 30.0 | 10.0 | 80.0 | 28.0 | 31.0 | 32.0 |
| Thu | NaN | 50.0 | 50.0 | NaN | 50.0 | 50.0 | NaN | 34.0 | 27.0 |
| Tue | 200.0 | 200.0 | 80.0 | 20.0 | 20.0 | 70.0 | 26.0 | 30.0 | 27.0 |
| Wed | NaN | 100.0 | 1000.0 | NaN | 80.0 | 90.0 | NaN | 33.0 | 32.0 |
첫 번째 인덱스 Location이 칼럼 레벨로 올라간 것을 확인할 수 있다.
인덱스에도 레벨(Depth)이 있어서 unstack(1)을 수행해 보면 두 번째 인덱스였던 요일이 칼럼 레벨로 올라간다.