TIL/Python

Python Library - Pandas를 통해 데이터를 변형하기(데이터 정렬 및 병합)

beady 2024. 11. 28. 16:16

Pandas는 데이터에 대한 다양한 기능을 제공한다.

오늘은 그 중에 데이터를 정렬하고 병합하는 기능에 대해 살펴보고자 한다.

또한 다양한 데이터프레임을 결합해서 원하는 새로운 데이터프레임을 만들어보자.

 

 

데이터 분석의 기본. 데이터 정렬

- sort_values()를 사용해서 값(value)을 기준으로 정렬하기

import pandas as pd

# 데이터프레임 생성
data = {
    '이름': ['철수', '영희', '민수', '지수'],
    '나이': [25, 30, 22, 35],
    '직업': ['학생', '회사원', '학생', '프리랜서']
}
df = pd.DataFrame(data)
print(df)
"""
   이름  나이    직업
0  철수  25    학생
1  영희  30   회사원
2  민수  22    학생
3  지수  35  프리랜서
"""

# '나이' 기준으로 오름차순 정렬
sorted_df = df.sort_values(by='나이')
print(sorted_df)
"""
   이름  나이    직업
2  민수  22    학생
0  철수  25    학생
1  영희  30   회사원
3  지수  35  프리랜서
"""

 

 

- 내림차순으로 정렬하려면, ascending=False로 지정하기

# '나이' 기준으로 내림차순 정렬
sorted_df = df.sort_values(by='나이', ascending=False)
print(sorted_df)
"""
   이름  나이    직업
3  지수  35  프리랜서
1  영희  30   회사원
0  철수  25    학생
2  민수  22    학생
"""

 

 

- sort_values()를 사용해 여러 열을 기준으로 정렬하기

- 열 기준으로 정렬 순서 각각 다르게 지정하기

import pandas as pd

data = {
    '이름': ['철수', '영희', '민수', '지수', '민재'],
    '나이': [25, 30, 22, 35, 30],
    '직업': ['학생', '회사원', '학생', '프리랜서', '축구선수']
}
df = pd.DataFrame(data)
print(df)
"""
   이름  나이    직업
0  철수  25    학생
1  영희  30   회사원
2  민수  22    학생
3  지수  35  프리랜서
4  민재  30  축구선수
"""

# '나이'를 기준으로, 같은 나이 내에서 '이름' 오름차순 정렬
sorted_df_3 = df.sort_values(by=['나이', '이름'])
print(sorted_df_3)
"""
   이름  나이    직업
2  민수  22    학생
0  철수  25    학생
4  민재  30  축구선수
1  영희  30   회사원
3  지수  35  프리랜서
"""

# '나이'를 기준으로 내림차순 정렬 후, 같은 나이 내에서 '이름' 내림차순 정렬
sorted_df_4 = df.sort_values(by=['나이', '이름'], ascending=False)
print(sorted_df_4)
"""
   이름  나이    직업
3  지수  35  프리랜서
1  영희  30   회사원
4  민재  30  축구선수
0  철수  25    학생
2  민수  22    학생
"""

# '나이'를 기준으로 내림차순 정렬 후, 같은 나이 내에서 '이름'을 오름차순 정렬
sorted_df_5 = df.sort_values(by=['나이', '이름'], ascending=[False, True])
print(sorted_df_5)
"""
   이름  나이    직업
3  지수  35  프리랜서
4  민재  30  축구선수
1  영희  30   회사원
0  철수  25    학생
2  민수  22    학생
"""

 

 

- sort_index()를 사용해 인덱스 기준으로 정렬하기

print(sorted_df)
"""
   이름  나이    직업
3  지수  35  프리랜서
1  영희  30   회사원
4  민재  30  축구선수
0  철수  25    학생
2  민수  22    학생
"""

# 인덱스를 기준으로 정렬
sorted_df.sort_index()
"""
   이름  나이    직업
0  철수  25    학생
1  영희  30   회사원
2  민수  22    학생
3  지수  35  프리랜서
4  민재  30  축구선수
"""

# 인덱스를 기준으로 내림차순 정렬
sorted_df.sort_index(ascending=False)
"""
   이름  나이    직업
4  민재  30  축구선수
3  지수  35  프리랜서
2  민수  22    학생
1  영희  30   회사원
0  철수  25    학생
"""

 

 

여러 개의 데이터 병합

- merge()를 사용해 공통 열을 기준으로 데이터프레임 병합(≒SQL의 INNER JOIN)

※ 공통값이 없는 데이터는 삭제됨에 주의

df1 = pd.DataFrame({
    '이름': ['철수', '영희', '민수'],
    '나이': [25, 30, 22]
})
print(df1)
'''
   이름  나이
0  철수  25
1  영희  30
2  민수  22
'''

df2 = pd.DataFrame({
    '이름': ['철수', '영희', '지수'],
    '직업': ['학생', '회사원', '프리랜서']
})
print(df2)
'''
   이름    직업
0  철수    학생
1  영희   회사원
2  지수  프리랜서
'''

# "이름"을 기준으로 병합
merge_df = pd.merge(df1, df2, on = '이름')
'''
print(merge_df)
   이름  나이   직업
0  철수  25   학생
1  영희  30  회사원
'''
# 공통값이 아닌 '민수'와 '지수'의 데이터는 삭제됨

 

그렇다면 삭제된 데이터를 유지하려면 어떻게 해야 될까?

 

how = "left"how = "right" / how = "outer" 값을 지정하기

# left(df1)을 기준으로 데이터를 유지하되, 없는 데이터는 NaN으로 출력
merge_df = pd.merge(df1, df2, on="이름", how = "left")
print(merge_df)
'''
   이름  나이   직업
0  철수  25   학생
1  영희  30  회사원
2  민수  22  NaN
'''

# right(df2)을 기준으로 데이터를 유지하되, 없는 데이터는 NaN으로 출력됨
merge_df = pd.merge(df1, df2, on="이름", how = "right")
print(merge_df)
'''
   이름    나이    직업
0  철수  25.0    학생
1  영희  30.0   회사원
2  지수   NaN  프리랜서
'''

# 모든 행의 데이터를 유지하되, 없는 데이터는 NaN으로 출력됨
merge_df = pd.merge(df1, df2, on="이름", how = "outer")
print(merge_df)
'''
   이름    나이    직업
0  민수  22.0   NaN
1  영희  30.0   회사원
2  지수   NaN  프리랜서
3  철수  25.0    학생
'''

 

 

- concat()을 사용해 행 또는 열 단위로 데이터프레임 연결하기

print(df1)
'''
   이름  나이
0  철수  25
1  영희  30
2  민수  22
'''

print(df2)
'''
   이름    직업
0  철수    학생
1  영희   회사원
2  지수  프리랜서
'''

# 행 단위(axis=0)로 데이터프레임 연결
concat_df = pd.concat([df1, df2], axis=0)
print(concat_df)
'''
   이름    나이    직업
0  철수  25.0   NaN
1  영희  30.0   NaN
2  민수  22.0   NaN
0  철수   NaN    학생
1  영희   NaN   회사원
2  지수   NaN  프리랜서
'''

# 열 단위(axis=1)로 데이터프레임 연결
concat_df = pd.concat([df1, df2], axis=1)
print(concat_df)
'''
   이름  나이  이름    직업
0  철수  25  철수    학생
1  영희  30  영희   회사원
2  민수  22  지수  프리랜서
'''

 

 

- join()을 사용해 인덱스를 기준으로 데이터프레임 병합하기

print(df1)
'''
   이름  나이
0  철수  25
1  영희  30
2  민수  22
'''

df3 = pd.DataFrame({
    '직업': ['학생', '회사원', '프리랜서'],
    '연봉': [2000, 3000, 4000]
}, index=['철수', '영희', '지수'])
print(df3)
'''
      직업    연봉
철수    학생  2000
영희   회사원  3000
지수  프리랜서  4000
'''

df1 = df1.set_index('이름') # '이름'열을 인덱스로 설정
print(d1)
'''
    나이
이름    
철수  25
영희  30
민수  22
'''

# 인덱스를 기준으로 병합
df1.join(df3)
'''
    나이   직업      연봉
이름                 
철수  25   학생  2000.0
영희  30  회사원  3000.0
민수  22  NaN     NaN
'''

 

 

데이터 그룹화 및 집계

- groupby() 함수를 사용해 특정 열 기준으로 그룹화

import pandas as pd

data = {
    '이름': ['철수', '영희', '민수', '지수', '철수', '영희'],
    '과목': ['수학', '수학', '과학', '과학', '영어', '영어'],
    '점수': [90, 85, 95, 80, 75, 88]
}
df = pd.DataFrame(data)
print(df)
'''
   이름  과목  점수
0  철수  수학  90
1  영희  수학  85
2  민수  과학  95
3  지수  과학  80
4  철수  영어  75
5  영희  영어  88
'''

grouped = df.groupby('이름') # '이름'을 기준으로 그릅화

 

 

- 집계 함수를 사용해서 다양한 요약 통계 계산하기

# 그룹에 대한('이름'을 기준) 각 학생의 평균 점수 계산
grouped['점수'].mean()
'''
이름
민수    95.0
영희    86.5
지수    80.0
철수    82.5
Name: 점수, dtype: float64
'''

# 그룹에 대한 각 학생의 점수 합계와 평균 계산
grouped['점수'].agg(['sum', 'mean']) # 여러 집계 함수 동시에 사용
'''
    sum  mean
이름           
민수   95  95.0
영희  173  86.5
지수   80  80.0
철수  165  82.5
'''

 

 

- 여러 열을 기준으로 그룹화하기

print(df)
'''
   이름  과목  점수
0  철수  수학  90
1  영희  수학  85
2  민수  과학  95
3  지수  과학  80
4  철수  영어  75
5  영희  영어  88
'''

# '이름'과 '과목'을 기준으로 그룹화 후 점수 합계를 계산
grouped_multi = df.groupby(['이름', '과목'])['점수'].sum()
print(grouped_multi)
'''
print(grouped_multi)
이름  과목
민수  과학    95
영희  수학    85
    영어    88
지수  과학    80
철수  수학    90
    영어    75
Name: 점수, dtype: int64
'''

 

 

데이터를 요약하고 분석해주는 피벗테이블 사용하기

- pivot_table() 함수 사용하기

# 이름 별 과목의 점수 평균을 계산하는 피벗 테이블 생성
pivot = pd.pivot_table(df, index = '이름', columns = '과목', values = '점수', aggfunc = 'mean')
print(pivot)
'''
과목    과학    수학    영어
이름                  
민수  95.0   NaN   NaN
영희   NaN  85.0  88.0
지수  80.0   NaN   NaN
철수   NaN  90.0  75.0
'''

여러 집계 함수를 사용하고 싶다면?

 

aggfunc에 여러 집계 함수를 지정해주면 된다.

# 점수의 평균과 점수의 합계를 계산하는 피벗 테이블 생성
pivot_multi = pd.pivot_table(df, index = '이름', columns = '과목', values = '점수', aggfunc =['mean', 'sum'])
print(pivot_multi)
'''
     mean               sum            
과목   과학   수학   영어   과학   수학   영어
이름                                    
민수  95.0   NaN   NaN  95.0   NaN   NaN
영희   NaN  85.0  88.0   NaN  85.0  88.0
지수  80.0   NaN   NaN  80.0   NaN   NaN
철수   NaN  90.0  75.0   NaN  90.0  75.0
'''

 

 

- margins = True를 사용해 각 행과 열의 전체 합계 추가하기

pivot_multi = pd.pivot_table(df, index = '이름', columns = '과목', values = '점수', aggfunc =['mean', 'sum'], margins = True)
print(pivot_multi)
'''
     mean                      sum                   
과목    과학   수학   영어  All    과학    수학    영어  All
이름                                                   
민수   95.0   NaN   NaN  95.0   95.0    NaN    NaN   95
영희    NaN  85.0  88.0  86.5    NaN   85.0   88.0  173
지수   80.0   NaN   NaN  80.0   80.0    NaN    NaN   80
철수    NaN  90.0  75.0  82.5    NaN   90.0   75.0  165
All  87.5  87.5  81.5  85.5  175.0  175.0  163.0  513
'''

※ 평균에 대해선 평균의 총 합이 아닌 전체 합계에 대한 평균을 보여줌에 주의해야 함

 

 

- fill_value = 0 값을 지정해서 피벗 테이블의 결측치(NaN)를 0으로 치환하기

pivot_multi = pd.pivot_table(df, index = '이름', columns = '과목', values = '점수', aggfunc =['mean', 'sum'], margins = True, fill_value = 0)
print(pivot_multi)
'''
     mean                    sum               
과목    과학   수학   영어  All   과학   수학  영어  All
이름                                             
민수   95.0   0.0   0.0  95.0   95    0    0   95
영희    0.0  85.0  88.0  86.5    0   85   88  173
지수   80.0   0.0   0.0  80.0   80    0    0   80
철수    0.0  90.0  75.0  82.5    0   90   75  165
All  87.5  87.5  81.5  85.5  175  175  163  513
'''

 

 

- 모든 그룹이 아닌 특정한 열의 집계 함수만 구하기

import pandas as pd

data = {
    '이름': ['철수', '영희', '민수', '지수', '철수', '영희'],
    '과목': ['수학', '수학', '과학', '과학', '영어', '영어'],
    '점수': [90, 85, 95, 80, 75, 88],
    '나이': [15, 14, 13, 12, 13, 12]
}
df = pd.DataFrame(data)
print(df)
'''
   이름  과목  점수  나이
0  철수  수학  90  15
1  영희  수학  85  14
2  민수  과학  95  13
3  지수  과학  80  12
4  철수  영어  75  13
5  영희  영어  88  12
'''

# 딕셔너리 형태로 agg에 필요한 집계 함수만 전달
agg_result = df.groupby('이름').agg({
    '점수':['mean', 'sum', 'max'],
    '나이':['max', 'sum']
})
print(agg_result)
'''
      점수           나이    
    mean  sum max max sum
이름                       
민수  95.0   95  95  13  13
영희  86.5  173  88  14  26
지수  80.0   80  80  12  12
철수  82.5  165  90  15  28
'''