인공지능 개발일지

[Pandas] groupby(), get_group()으로 범주형 칼럼 그룹화/그룹 객체 생성 본문

인공지능/데이터 분석

[Pandas] groupby(), get_group()으로 범주형 칼럼 그룹화/그룹 객체 생성

Prcnsi 2022. 9. 12. 01:17
728x90

 

안녕하세요~ 이번 시간에는 범주형 칼럼에 대해서 카테고리별로 그룹화하고

그룹별로 DataFrame을 반환하는 방법에 대해알아 보겠습니다.


 

 이 groupby() 함수도 기능이 많긴 하던데 저는 제목에 나온 대로 그룹화하는 방법과 그룹 객체를 생성하는 방법에 대해서만 정리해 보았습니다.  실제로 제일 많이 사용되기도 하고요.

 

왜 때문인진 모르겠는데 제가 이 작업을 할 때 아무 생각 없이 아래와 같이 비효율적으로 했었습니다.

근데 하다 보니 귀찮아서 그룹화에는 뭔가 이 sort 해주는 기능이 있을 것 같았는데 찾아보니 역시 있더군요..^^

# 사용가능한 노선만 철도별로 분리
notUse_train1=notUse_train[notUse_train['노선명']=='경강선']
notUse_train2=notUse_train[notUse_train['노선명']=='경부선']
notUse_train3=notUse_train[notUse_train['노선명']=='경춘선']
notUse_train4=notUse_train[notUse_train['노선명']=='수여선']
notUse_train5=notUse_train[notUse_train['노선명']=='수인선']
notUse_train6=notUse_train[notUse_train['노선명']=='중앙선']
notUse_train7=notUse_train[notUse_train['노선명']=='경부고속선']
notUse_train8=notUse_train[notUse_train['노선명']=='경전선']
notUse_train9=notUse_train[notUse_train['노선명']=='동해남부선']
notUse_train10=notUse_train[notUse_train['노선명']=='동해중부 미건설선']
notUse_train11=notUse_train[notUse_train['노선명']=='산재 유휴부지']
notUse_train12=notUse_train[notUse_train['노선명']=='임항선']
notUse_train13=notUse_train[notUse_train['노선명']=='대전남연결선']
notUse_train14=notUse_train[notUse_train['노선명']=='문경선']
notUse_train15=notUse_train[notUse_train['노선명']=='장항선']
notUse_train16=notUse_train[notUse_train['노선명']=='경전선 추가']
notUse_train17=notUse_train[notUse_train['노선명']=='삼학도선']
notUse_train18=notUse_train[notUse_train['노선명']=='전라선']
notUse_train19=notUse_train[notUse_train['노선명']=='호남선']
notUse_train20=notUse_train[notUse_train['노선명']=='영동선']
notUse_train21=notUse_train[notUse_train['노선명']=='태백선']
notUse_train22=notUse_train[notUse_train['노선명']=='수인선(선로상부)']
notUse_train23=notUse_train[notUse_train['노선명']=='경의선(선로상부)']
notUse_train24=notUse_train[notUse_train['노선명']=='고속선(선로상부)']
notUse_train25=notUse_train[notUse_train['노선명']=='호남고속선']

 

그래서 한 번 정리해 보았습니다.

아래를 보면 예시 데이터가 있습니다. 이 데이터는 폐철도 관련 칼럼으로 국가철도공단에서 받아온 폐철도 데이터입니다.

여기서  '노선명' 칼럼은 25개의 노선 카테고리가 있는 범주형 칼럼입니다. 따라서, 이들을 노선별로 그룹화해주겠습니다. 

 data
[Output]
지역본부	재산 소재지	노선명	면적(공부)	유형분류	현재 사용현황	향후 사용계획 및 추진사항
0	수도권본부	경기도 이천시 부발읍 아미리 35-25	경강선	207.0	기타	잔여지	활용계획 검토 중
1	수도권본부	경기도 이천시 부발읍 아미리 산47-4	경강선	1173.0	기타	잔여지	활용계획 검토 중
2	수도권본부	경기도 여주군 능서면 용은리 452-7	경강선	303.0	기타	잔여지	활용계획 검토 중
3	수도권본부	경기도 광주시 삼동 222-8	경강선	272.0	기타	잔여지	활용계획 검토 중
4	수도권본부	경기도 광주시 장지동 496-7	경강선	204.0	기타	잔여지	활용계획 검토 중
...	...	...	...	...	...	...	...
19895	충청본부	경상북도 김천시 남면 옥산리 800	경부고속선	1036.0	활용	미사용(나대지)	사용허가 추진(주차장)
19896	충청본부	경상북도 김천시 남면 옥산리 928-17	경부고속선	817.0	활용	미사용(나대지)	사용허가 추진(주차장)
19897	충청본부	충청북도 청주시 흥덕구 오송읍 봉산리 36-15	경부고속선	2549.0	활용	사용_철도사업(오송창고)	계속 사용
19898	충청본부	충청북도 청주시 흥덕구 오송읍 봉산리 43-2	경부고속선	297.0	활용	사용_철도사업(오송창고)	계속 사용
19899	충청본부	충청북도 청주시 흥덕구 오송읍 봉산리 35-13	경부고속선	1623.0	활용	사용_철도사업(사무실)	계속 사용
19900 rows × 7 columns

 

각각의 목록은 unique() 함수로 확인할 수 있습니다.

data['노선명'].unique()
[Output]
array(['경강선', '경부선', '경춘선', '수여선', '수인선', '중앙선', '경부고속선', '경전선', '동해남부선',
       '동해중부 미건설선', '산재 유휴부지', '임항선', '대전남연결선', '문경선', '장항선', '경전선 추가',
       '삼학도선', '전라선', '호남선', '영동선', '태백선', '수인선(선로상부)', '경의선(선로상부)',
       '고속선(선로상부)', '호남고속선'], dtype=object)

 

그럼 노선별로 이 데이터들을 그룹화해봅시다. 우선 그룹 객체를 생성해 줍니다. 

이의 문법은 아래와 같습니다.

 

객체 변수=그룹화할_데이터 프레임. groupby('기준_칼럼명')

그럼 위 예제에서는 아래 코드가 됩니다.

Available_group=data.groupby('노선명')

 

그리고 이를 출력해 보면 잘 그룹화가 된 것을 확인할 수 있습니다.

Available_group
[Ouput]
<pandas.core.groupby.generic.DataFrameGroupBy object at 0x7fd5fa3caf90>

생성된 그룹 객체는 '카테고리(key)'와 '카테고리별 데이터(group)''를 튜플 형태로 가지고 있습니다.

그리고 이들을 각각 key와 group으로 부릅니다.

 

 

 

이 값들은 반복문을 통해 확인할 수 있습니다. 기본 반복문의 구조 for i in [대상]의 형식에서 i의 첫 번째 인자로 key를 담을 변수 두 번째로는 그에 해당하는 데이터를 담을 변수를 적어주고 iterator 자리에 그룹을 주면 아래와 같이 편안하게 노선별로 잘 분리된 것을 확인할 수 있습니다.

 

for key, group in Available_group:
    print("* key", key)
    print("* count", len(group))
    print(group.head())
    print('\n')
    

# 위의 코드와 아래 코드는 동작이 정확히 동일함 - 변수명보다 위치가 중요 (a,b)
# for a, b in Available_group:
#     print("* key", a)
#     print("* count", len(b))
#     print(group.head())
#     print('\n')
[Output]
* key 경강선
* count 31
    지역본부                 재산 소재지  노선명   면적(공부)  유형분류 현재 사용현황 향후 사용계획 및 추진사항
0  수도권본부  경기도 이천시 부발읍 아미리 35-25  경강선     207.0   기타     잔여지      활용계획 검토 중
1  수도권본부  경기도 이천시 부발읍 아미리 산47-4  경강선    1173.0   기타     잔여지      활용계획 검토 중
2  수도권본부  경기도 여주군 능서면 용은리 452-7  경강선     303.0   기타     잔여지      활용계획 검토 중
3  수도권본부       경기도 광주시 삼동 222-8  경강선     272.0   기타     잔여지      활용계획 검토 중
4  수도권본부      경기도 광주시 장지동 496-7  경강선     204.0   기타     잔여지      활용계획 검토 중

... ... ... ... ... ... ... ...

* key 호남선
* count 51
       지역본부              재산 소재지  노선명   면적(공부)  유형분류        현재 사용현황  \
16008  호남본부    전라남도 목포시 상동 1045  호남선     939.0   활용  목포시 사용허가(공원화)   
16009  호남본부  전라남도 목포시 상동 1045ㅡ2  호남선    4858.0   활용  목포시 사용허가(공원화)   
16010  호남본부  전라남도 목포시 상동 1045ㅡ3  호남선     562.0   활용  목포시 사용허가(공원화)   
16011  호남본부  전라남도 목포시 상동 1045ㅡ4  호남선   16385.0   활용  목포시 사용허가(공원화)   
16012  호남본부  전라남도 목포시 상동 1045ㅡ5  호남선     171.0   활용      사용허가(농경지)   

      향후 사용계획 및 추진사항  
16008  목포시 사용허가(공원화)  
16009  목포시 사용허가(공원화)  
16010  목포시 사용허가(공원화)  
16011  목포시 사용허가(공원화)  
16012      사용허가(농경지)

 

 

그리고 이 전체 객체에 mean() 메서드를 쓰면 카테고리별로 평균값을 구해줍니다.(편안하죠?)

Available_group.mean()
[Output]
	면적(공부)
노선명	
경강선	388.000000
경부고속선	1638.852941
경부선	1405.066085
경의선(선로상부)	2459.806452
경전선	918.912781
경전선 추가	818.144737
경춘선	809.850108
고속선(선로상부)	834.923077
대전남연결선	724.478022
동해남부선	645.809717
동해중부 미건설선	863.855828
문경선	491.444444
산재 유휴부지	1651.145299
수여선	343.093633
수인선	793.714286
수인선(선로상부)	1643.090909
영동선	3479.480874
임항선	1073.462687
장항선	1535.837838
전라선	1687.587774
중앙선	1088.170360
호남고속선	1351.857143
호남선	4112.882353

 

그룹 객체 추출

 group 추출은 get_group('카테고리명') 함수로 할 수 있다. 그리고 이는 그 결과를 반환해 카테고리별로 데이터를 분리할 수가 있다. 이는 물론 아래 주석 처리한 기본 검색 기능으로도 할 수 있지만 groupby를 활용하면 간결할뿐더러 처리 이후 다시 합치는 것 외에 다양한 기능을 한 번에 해줘서 매우 편리하다. 

Available_group.get_group('경강선')
# Available_group[Available_group['노선명']=='경강선']
[Output]
	지역본부	재산 소재지	노선명	면적(공부)	유형분류	현재 사용현황	향후 사용계획 및 추진사항
0	수도권본부	경기도 이천시 부발읍 아미리 35-25	경강선	207.0	기타	잔여지	활용계획 검토 중
1	수도권본부	경기도 이천시 부발읍 아미리 산47-4	경강선	1173.0	기타	잔여지	활용계획 검토 중
2	수도권본부	경기도 여주군 능서면 용은리 452-7	경강선	303.0	기타	잔여지	활용계획 검토 중
3	수도권본부	경기도 광주시 삼동 222-8	경강선	272.0	기타	잔여지	활용계획 검토 중
4	수도권본부	경기도 광주시 장지동 496-7	경강선	204.0	기타	잔여지	활용계획 검토 중
5	수도권본부	경기도 광주시 실촌읍 곤지암리 155	경강선	31.0	기타	잔여지	활용계획 검토 중
6	수도권본부	경기도 이천시 부발읍 신하리 543-3	경강선	331.0	기타	잔여지	활용계획 검토 중
7	수도권본부	경기도 이천시 부발읍 가좌리 196-2	경강선	589.0	기타	잔여지	활용계획 검토 중
8	수도권본부	경기도 이천시 부발읍 가좌리 196-4	경강선	354.0	기타	잔여지	활용계획 검토 중
9	수도권본부	경기도 이천시 부발읍 가좌리 산41-4	경강선	45.0	기타	잔여지	활용계획 검토 중
10	수도권본부	경기도 이천시 부발읍 아미리 1197-4	경강선	425.0	기타	잔여지	활용계획 검토 중
11	수도권본부	경기도 이천시 부발읍 아미리 15	경강선	334.0	기타	잔여지	활용계획 검토 중
12	수도권본부	경기도 이천시 부발읍 아미리 232	경강선	56.0	기타	잔여지	활용계획 검토 중
13	수도권본부	경기도 이천시 부발읍 아미리 산69-11	경강선	150.0	기타	잔여지	활용계획 검토 중
    ... ... ... ... ... ... ... ...

 

그리고 위의 반환 값을 객체에 담아주면 간단하게 노선별로 데이터를 분리할 수 있다.

avail1=Available_group.get_group('경강선')

 

 

 

참고로 groupby.agg 함수는 2개 이상의 함수를 각각에 맵핑한 결과를 볼 수도 있다. 

이외에도 다양한 기능이 있지만 가장 기본적인 내용만 정리해보았다.

 

728x90