파이썬 머신러닝 판다스 데이터분석

4주차- 데이터프레임의 다양한 응용

humpark 2024. 8. 22. 20:46

1. 함수 매핑

함수 매핑은 시리즈 또는 데이터프레임의 개별 원소를 특정 함수에 일대일 대응시키는 과정임

 

1-1 개별 원소에 함수 매핑

시리즈 객체에 apply() 메소드를 적용하면 인자로 전달하는 매핑 함수에 시리즈의 모든 원소를 하나씩 입력하고 함수의 리턴값을 돌려받는다.

#시리즈 원소에 함수 매핑
Series 객체.apply(매핑함수)
import seaborn as sns

#titanic 데이터셋에서 age, fare 2개 열을 선택하여 데이터프레임 만들기
titanic= sns.load_dataset('titanic')
df= titanic.loc[:, ['age', 'fare']]
df['ten'] = 10
print(df.head())

#시리즈 의 원소에 함수 정의하기
#사용자 함수 정의
def add_10(n):
    return n + 10       #10을 더하는 함수
def add_two_obj(a,b):
    return a + b        #두 객체의 합

print(add_10(10))
print(add_two_obj(10,10))

#시리즈 원소에 apply() 적용
#시리즈 객체에 적용
sr1= df['age'].apply(add_10)    #n= df['age']의 모든 원소
print(sr1.head())
print('\n')

#시리즈 객체와 숫자에 적용: 2개의 인수(시리즈 + 숫자)
sr2= df['age'].apply(add_two_obj, b= 10)    #a= df['age'] 의 모든 원소
print(sr2.head())
print('\n')

#lambda 함수 활용: 시리즈 객체에 적용
sr3= df['age'].apply(lambda x: add_10(x))   #x= df['age']
print(sr3.head())

apply() 메소드를 이용하여

1. df['age'] 열에 add_10 함수를 매핑하면 모든 원소에 숫자 10을 더한다.

2. df['age'] 열에 add_two_obj 함수를 매핑하면 모든 원소에 숫자 10을 더한다.

3. df['age'] 열에 lambda함수를 매핑하면  add_10 함수의 리턴값을 저장한다.

 

  • 데이터프레임 원소에 함수 매핑

데이터프레임의 개별 원소에 특정 함수를 매핑하려면 applymap() 메소드를 이용한다.

매핑 함수에 데이터프레임의 각 원소를 하나씩 넣어서 리턴값으로 돌려받는다.

원소의 원래 위치에 매핑 함수의 리턴값을 입력하여 동일한 형태의 데이터프레임이 만들어진다.

# 데이터프레임의 원소에 함수 매핑
DataFrame객체.applymap(매핑 함수)
# 데이터프레임에 add_10() 함수를 매핑 적용
df_map = df.applymap(add_10)

 

1-2 시리즈 객체에 함수 매핑

  • 데이터프레임의 각 열에 함수 매핑

데이터프레임에 apply(axis=0) 메소드를 적용하면 모든 열을 하나씩 분리하여 매핑함수의 인자로 각 열이 전달된다.

매핑 함수에 따라 반환되는 객체의 종류가 다르다. 예를들어 시리즈를 입력받고 시리즈를 반환하는 함수를 매핑하면, 데이터프레임을 반환한다

#데이터프레임의 열에 함수 매핑
df.apply(매핑함수, axis=0)
import seaborn as sns

#titanic 데이터셋에서 age, fare 2개 열을 선택하여 데이터프레임 만들기
titanic= sns.load_dataset('titanic')
df= titanic.loc[:, ['age', 'fare']]

#사용자 함수 정의
def missing_value(series):      #시리즈를 인자로 전달
    return series.isnull()      #불린 시리즈를 반환

#데이터프레임에 apply 메소드를 적용
result= df.apply(missing_value, axis=0)
print(result.head())

 

한편 시리즈를 입력받아서 하나의 값을 반환하는 함수를 매핑하면 시리즈를 반환한다.

#사용자 함수 정의
def min_max(x):     #최대값 - 최소값
    return x.max() - x.min()

#데이터프레임에 apply 메소드를 적용
result = df.apply(min_max)  #기본값으로 axis=0
print(result)

 

  • 데이터프레임의 각 행에 함수 매핑

데이터프레임 객체에 axis=1 메소드를 적용하면 데이터프레임의 각 행을 매핑 함수의 인자로 전달한다.

데이터프레임의 행 인덱스가 매핑 결과로 반환되는 시리즈의 인덱스가 된다.

시리즈의 인덱스에 매칭되는 데이터 값에는 각 행의 데이터를 함수에 적용한 리턴값을 가져온다

#데이터프레임의 행에 함수 매핑
df.apply(매핑함수, axis=1)
import seaborn as sns

#titanic 데이터셋에서 age, fare 2개 열을 선택하여 데이터프레임 만들기
titanic= sns.load_dataset('titanic')
df= titanic.loc[:, ['age', 'fare']]
df['ten'] = 10

#사용자 함수 정의
def add_two_obj(a,b): 
    return a + b

#데이터프레임의 2개 열에 적용
#x= df, a=df['age'], b=df['ten']
df['add']= df.apply(lambda x: add_two_obj(x['age'], x['ten']), axis=1)
print(df.head())

#결과
    age     fare  ten
0  22.0   7.2500   10
1  38.0  71.2833   10
2  26.0   7.9250   10
3  35.0  53.1000   10
4  35.0   8.0500   10

    age     fare  ten   add
0  22.0   7.2500   10  32.0
1  38.0  71.2833   10  48.0
2  26.0   7.9250   10  36.0
3  35.0  53.1000   10  45.0
4  35.0   8.0500   10  45.0

 

1-3 데이터프레임 객체에 함수 매핑

데이터프레임 객체를 함수에 매핑하려면 pipe() 메소드를 이용한다. 이때 사용하는 함수가 반환하는 리턴값에 따라 pipe() 메소드가 반환하는 객체의 종류가 결정된다. 데이터프레임을 반환하는 경우, 시리즈를 반환하는 경우, 개별 값을 반환하는 경우로 나눌 수 있다

#데이터프레임 객체에 함수 매핑
df.pipe(매핑 함수)
  • 데이터프레임 반환
# 각 열의 NaN 찾기 - 데이터프레임을 전달하면 데이터프레임 반환
def missing_value(x):
    return x.isnull()

# 데이터프레임에 pipe() 적용 (함수 매핑)
result_df = df.pipe(missing_value)
print(result_df.head())
print(type(result_df))

# 실행 결과 - 데이터프레임으로 반환
     age   fare
0  False  False
1  False  False
2  False  False
3  False  False
4  False  False
<class 'pandas.core.frame.DataFrame'>
  • 시리즈 반환
# 각 열의 NaN 찾기 - 데이터프레임을 전달하면 시리즈 반환
def missing_count(x):
    return missing_value(x).sum()

# 데이터프레임에 pipe() 적용 (함수 매핑)
result_series = df.pipe(missing_count)
print(result_series)
print(type(result_series))

# 실행 결과
age     177
fare      0
dtype: int64
<class 'pandas.core.series.Series'>
  • 개별 값 반환
# 각 열의 NaN 찾기 - 데이터프레임을 전달하면 값 반환
def total_number_missing(x):
    return missing_count(x).sum()

# 데이터프레임에 pipe() 적용 (함수 매핑)
result_value = df.pipe(total_number_missing)
print(result_value)
print(type(result_value))

# 실행 결과
177
<class 'numpy.int64'>

 

 

2. 열 재구성

2-1 열 순서 변경

#데이터프레임의 열 순서 변경
df[재구성한 열이름의 리스트]

#열 이름의 리스트 만들기
columns = list(df.columns.values)	#기존 열 이름이 리스트로 반환

#열 이름을 알파벳 순으로 정리하기
columns_sorted= sorted(colums)	#알파벳 순으로 정렬
df_sorted= df[colums_sorted]

#열 이름을 알파벳 역순으로 정리하기
colums_reversed= list(reversed(columns))
df_reversed= df[columns_reverse]

#열 이름을 임의의 순서로 재배치하기
columns_customed= ['pclass', 'sex', 'survived']
df_customed= df[columns_customed]

 

2-2 열 분리

연월일처럼 하나의 열이 여러개의 정보를 담고있을때 서로 분리해서 사용하는 경우가 있다.

#연, 월, 일 데이터 분리하기
df['연월일']= df['연월일'].astype('str')	#문자열 메소드 사용을 위해 자료형으로 변경
dates= df['연월일'].str.split('-')	#문자열 split() 메소드로 분리

#분리된 정보를 각각 새로운 열에 담아 df에 추가하기
df['연']= dates.str.get(0)	#dates 변수의 원소 리스트의 0번째 인덱스 값
df['월']= dates.str.get(1)	#dates 변수의 원소 리스트의 1번째 인덱스 값 
df['일']= dates.str.get(2)	#dates 변수의 원소 리스트의 2번째 인덱스 값

 

 

3. 필터링

시리즈 또는 데이터프레임의 데이터중에서 조건식을 만족하는 원소만 따로 추출하는 개념.

 

3-1 불린 인덱싱

시리즈 객체에 어떤 조건식을 적용하면 각 원소에 대해 참/거짓을 판별하여 불린(참, 거짓) 값으로 구성된 시리즈를 반환한다. 이때 참에 해당하는 데이터 값을 따로 선택할 수 있는데, 많은 데이터중에서 어떤 조건을 만족하는 데이터만을 추출하는 필터링 기법.

데이터프레임의 각 열은 시리즈 객체이므로 조건식을 적용하면 각 원소가 조건식을 만족하는지 여부를 참과 거짓으로 불릿 시리즈를 만들 수 있음.

#데이터프레임 불린 인덱싱
df[불린 시리즈]
import seaborn as sns

#titanic 데이터셋 로딩
titanic= sns.load_dataset('titanic')

#나이가 10대(10~19)인 승객만 따로 선택
mask1= (titanic.age >= 10) & (titanic.age < 20)
df_teenage= titanic.loc[mask1, :]

#나이가 10세 미만(0~9)이고 여성인 승객만 따로 선택
mask2= (titanic.age <10) & (titanic.sex == 'female')
df_female_under10= titanic.loc[mask2, :])

#나이가 10세 미만(0~9) 또는 60세 이상인 승객의 age, sex, alone 열만 선택
mask3= (titanic.age < 10) | (titanic.age >= 60)
df_under10_morthan60 = titanic.loc[mask3, ['age', 'sex', 'alone']]

 

3-2 isin() 메소드 활용

데이터프레임의 열에 isin() 메소드를 적용하면 특정 값을 가진 행들을 따로 추출할 수 있다.

이때 isin() 메소드에 데이터프레임의 열에서 추출하려는 값들로 만든 리스트를 전달한다

#isin() 메소드를 활용한 필터링
df.isin(추출 값의 리스트)

#함께 탑승한 형제 또는 배우자의 수가 3, 4, 5인 승객만 따로 추출 - 불린 인덱싱
mask3 = titanic['sibsp'] == 3
mask4 = titanic['sibsp'] == 4
mask5 = titanic['sibsp'] == 5
df_boolean= titanic[mask3 | mask4 | mask5]

#isin() 메소드 활용하여 동일한 조건으로 추출
isin_filter= titanic['sibsp'].isin([3,4,5])
df_isin= titanic[isin_filter]

 

 

4. 데이터프레임 합치기

데이터가 여러 군데 나누어져 있을 때 하나로 합치거나 데이터를 연결해야 하는 경우가 있다.

4-1 데이터프레임 연결

서로 다른 데이터프레임들의 구성 형태와 속성이 균일하다면, 행 또는 열 중에 어느 한 방향으로 이어 붙여도 데이터의 일관성을 유지할 수 있음

기존 데이터프레임 형태를 유지하면서 이어 붙이는 개념으로 판다스 concat() 함수를 이용

#데이터프레밍 연결하기
pd.concat(데이터프레임의 리스트)

아래의 그림과 같이 축방향을 지정하지 않으면 기본 옵션(axis= 0)이 적용되어 위 아래 행 방향으로 연결된다. 

열 이름에 대해서는 join ='outer' 옵션이 기본 적용되어 df1의 열이름(A,B,C)와 df2의 열이름 (B, C, D, E)의 합집합으로 연결 데이터프레임의 열 이름 배열(A,B,C,D,E)를 구성한다

join= 'inner' 의 경우 데이터프레임에 공통으로 속하는 교집합 (B,C)가 기준이 된다

import pandas as pd
# 데이터프레임 만들기
df1 = pd.DataFrame({'a': ['a0', 'a1', 'a2', 'a3'],
                    'b': ['b0', 'b1', 'b2', 'b3'],
                    'c': ['c0', 'c1', 'c2', 'c3']},
                    index=[0, 1, 2, 3])

df2 = pd.DataFrame({'a': ['a2', 'a3', 'a4', 'a5'],
                    'b': ['b2', 'b3', 'b4', 'b5'],
                    'c': ['c2', 'c3', 'c4', 'c5'],
                    'd': ['d2', 'd3', 'd4', 'd5']},
                    index=[2, 3, 4, 5])
  • axis= 0 옵션
#2개의 데이터프레임을 위 아래 행 방향으로 이어 붙이듯 연결하기 axis=0 디폴트 옵션
result1= pd.concat([df1, df2])
print(result1,'\n')

#결과값
    a   b   c    d
0  a0  b0  c0  NaN
1  a1  b1  c1  NaN
2  a2  b2  c2  NaN
3  a3  b3  c3  NaN
2  a2  b2  c2   d2
3  a3  b3  c3   d3
4  a4  b4  c4   d4
5  a5  b5  c5   d5
#ignore_index=True 옵션을 통해서 기존의 행 인덱스를 무시하고 새로운 행 인덱스를 설정
result2= pd.concat([df1,df2], ignore_index= True)

#결과값
    a   b   c    d
0  a0  b0  c0  NaN
1  a1  b1  c1  NaN
2  a2  b2  c2  NaN
3  a3  b3  c3  NaN
4  a2  b2  c2   d2
5  a3  b3  c3   d3
6  a4  b4  c4   d4
7  a5  b5  c5   d5

 

  • axis=1 옵션

axis=1 옵션을 사용하면 데이터프레임을 좌우 열 방향으로 연결한다. 따라서 기존 열 이름 배열이 그대로 유지된다. 연결되는 데이터프레임의 행 인덱스는, join='outer' 옵션이 기본값으로 적용되어 각 데이터프레임의 행 인덱스들의 합집합으로 구성된다.

#2개의 데이터프레임을 좌우 열 방향으로 이어 붙이듯 연결하기
result3= pd.concat([df1, df2], axis=1)

#결과값
     a    b    c    a    b    c    d
0   a0   b0   c0  NaN  NaN  NaN  NaN
1   a1   b1   c1  NaN  NaN  NaN  NaN
2   a2   b2   c2   a2   b2   c2   d2
3   a3   b3   c3   a3   b3   c3   d3
4  NaN  NaN  NaN   a4   b4   c4   d4
5  NaN  NaN  NaN   a5   b5   c5   d5

#join= 'inner' 옵션을 통해서 두 데이터프레임의 행 인덱스의 교집합을 기준으로 사용하기
result3_in= pd.concat([df1, df2], axis=1, join='inner')

#결과값
    a   b   c   a   b   c   d
2  a2  b2  c2  a2  b2  c2  d2
3  a3  b3  c3  a3  b3  c3  d3

 

  • 데이터프레임과 시리즈를 좌우 열 방향으로 연결하기

데이터프레임에 열을 추가하는것과 같다. 이때 시리즈의 이름이 데이터프레임의 열 이름으로 변환된다.

단, 데이터프레임의 행 인덱스와 시리즈의 인덱스가 같아야 한다. 공통 인덱스가 없을경우 NaN 처리된다.

# 시리즈 만들기
sr1 = pd.Series(['e0','e1','e2','e3'], name='e')
sr2 = pd.Series(['f0','f1','f2'], name='f', index=[3,4,5])
sr3 = pd.Series(['g0','g1','g2','g3'], name='g')

# df1과 sr1을 좌우 열 방향으로 연결
result4 = pd.concat([df1,sr1], axis=1)

# 실행 결과
    a   b   c   e
0  a0  b0  c0  e0
1  a1  b1  c1  e1
2  a2  b2  c2  e2
3  a3  b3  c3  e3

# df2와 sr2를 좌우 열 방향으로 연결
result5 = pd.concat([df2,sr2], axis=1, sort=True)
print(result5)

# 실행 결과
    a   b   c   d    f
2  a2  b2  c2  d2  NaN
3  a3  b3  c3  d3   f0
4  a4  b4  c4  d4   f1
5  a5  b5  c5  d5   f2

 

  • 시리즈끼리 연결하기

concat() 함수를 통해서 시리즈끼리 서로 연결 할 수 있다. axis=1 옵션을 적용하면 좌우 열 방향으로 연결하여 데이터프레임이 된다. 한편 axis=0 옵션을 적용하면 위아래 행 방향으로 길게 연결되어 하나의 시리즈가 된다

#sr1 과 sr3을 좌우 열 방향으로 연결하기
result6= pd.concat([sr1,sr3], axis=1)

result7= pd.concat([sr1,sr3], axis=0)

#결과값
    e   g
0  e0  g0
1  e1  g1
2  e2  g2
3  e3  g3
0    e0
1    e1
2    e2
3    e3
0    g0
1    g1
2    g2
3    g3
dtype: object

 

4-2 데이터프레임 병합

SQL 함수의 join과 비슷한 방식으로 어떤 기준에 의해 두 데이터프레임을 병합하는 방식

이때 기준이 되는 열이나 인덱스를 key라고 부른다. 키가 되는 열이나 인덱스는 반드시 양쪽 데이터프레임에 모두 존재햐야 한다.

#데이터프레임의 병합
pd.merge(df_left, df_rigt, how= 'inner', on=기준되는 행이나 열 인덱스)

import pandas as pd

#주식 데이터를 가져와서 데이터프레임 만들기
df1= pd.read_excel('C:/Users/sajog/Downloads/5674-980/pandas-data-analysis-main/part6/data/stock_price.xlsx', engine= 'openpyxl')
df2= pd.read_excel('C:/Users/sajog/Downloads/5674-980/pandas-data-analysis-main/part6/data/stock_valuation.xlsx', engine= 'openpyxl')


#데이터프레임 합치기- 공통 열 기준 교집합
merge_inner= pd.merge(df1, df2)

#데이터프레임 합치기- id 기준 합집합
merge_outer= pd.merge(df1, df2, how= 'outer', on= 'id')

#데이터프레임 합치기- 왼쪽 데이터프레임 기준, 키 값 분리
merge_left= pd.merge(df1, df2, how= 'left', left_on= 'stock_name', right_on= 'name')
#데이터프레임을 결합하고 불린 인덱싱을 사용하여 합쳐진 데이터프레임에서 원하는 데이터 찾기
price= df1[df1['price'] < 5000]

value= pd.merge(price,df2)

#결과값
0  204210  모두투어리츠  3093.333333   3475  모두투어리츠  85.166667  5335   

         per       pbr  
0  40.802348  0.651359

 

 

4-3 데이터프레임 결합

판다스 join() 메소드는 merge() 함수를 기반으로 만들어졌기 때문에 기본 작동 방식이 서로 비슷하다. 하지만 join() 메소드는 두 데이터프레임의 행 인덱스를 기준으로 결합하는 점에서 merge() 함수와 차이가 있다.

하지만 join() 메소드에서 on= keys 옵션을 설정하면 행 인덱스 대신 다른 열을 기준으로 결합하는 것이 가능하다

#행 인덱스 기준으로 결합
df1.join(df2, how='left')
import pandas as pd

#주식 데이터를 가져와서 데이터프레임 만들기
df1= pd.read_excel('C:/Users/sajog/Downloads/5674-980/pandas-data-analysis-main/part6/data/stock_price.xlsx',index_col='id', engine= 'openpyxl')
df2= pd.read_excel('C:/Users/sajog/Downloads/5674-980/pandas-data-analysis-main/part6/data/stock_valuation.xlsx',index_col='id', engine= 'openpyxl')


df3 =df1.join(df2, how='inner')	#또는 'left' 이런식도 가능함
print(df3)

#결과값
          stock_name          value   price          name           eps  \
id                                                                        
130960        CJ E&M   58540.666667   98900        CJ E&M   6301.333333   
139480        이마트  239230.833333  254500        이마트  18268.166667   
145990        삼양사   82750.000000   82000        삼양사   5741.000000   
185750        종근당   40293.666667  100500        종근당   3990.333333   
204210  모두투어리츠    3093.333333    3475  모두투어리츠     85.166667   

           bps        per       pbr  
id                                   
130960   54068  15.695091  1.829178  
139480  295780  13.931338  0.860437  
145990  108090  14.283226  0.758627  
185750   40684  25.185866  2.470259  
204210    5335  40.802348  0.651359

 

 

5. 그룹 연산

복잡한 데이터를 어떤 기준에 따라 여러 그룹으로 나눠 계산하기

groupby() 메소드를 이용하고, 총 3개의 단계가 있다

1. 분할(split): 데이터를 특정 조건에 의해 분할

2. 적용(apply): 데이터를 집계, 변환, 필터링하는데 필요한 메소드 적용

3. 결합(combine): 2단계의 처리 결과를 하나로 결합

 

5-1 그룹 객체 만들기(분할 단계)

  • 1개 열을 기준으로 그룹화
#그룹 분할
df.groupby(기준이 되는열)
import pandas as pd
import seaborn as sns

#titanic 데이터셋에서 age, sex 등 5개의 열을 선택하여 데이터프레임 만들기
titanic= sns.load_dataset('titanic')
df= titanic.loc[:, ['age', 'sex', 'class', 'fare', 'survived']]

print('승객 수:', len(df))
print(df.head())

#결과값
승객 수: 891
    age     sex  class     fare  survived
0  22.0    male  Third   7.2500         0
1  38.0  female  First  71.2833         1
2  26.0  female  Third   7.9250         1
3  35.0  female  First  53.1000         1
4  35.0    male  Third   8.0500         0
#class 열을 기준으로 분할
grouped= df.groupby(['class'])
# 그룹 객체를 iteration으로 출력: head() 메소드로 첫 5행만을 출력
for key, group in grouped:
    print('* key:',key)
    print('* number:',len(group))
    print(group.head())
    
# 연산 메소드 적용
average = grouped.mean()

# 개별 그룹 선택
group3 = grouped.get_group('Third')

 

  • 여러 열을 기준으로 그룹화
#여러개의 기준 값을 통해 그룹화
df.groupby(기준이 되는 열의 리스트)

 

#class 열, sex 열을 기준으로 분할
grouped_two = df.groupby(['class', 'sex'])

#grouped_two 그룹 객체를 iteration 으로 출력
for key, group in grouped_two:
    print('* key:',key)
    print('* number:',len(group))
    print(group.head())
    
#결과값
* key: ('First', 'female')
* number: 94
     age     sex  class      fare  survived
1   38.0  female  First   71.2833         1
3   35.0  female  First   53.1000         1
11  58.0  female  First   26.5500         1
31   NaN  female  First  146.5208         1
52  49.0  female  First   76.7292         1
* key: ('First', 'male')

#이런 방식으로 6개의 조합이 나옴
#grouped_two 그룹 객체에 연산 메소드 적용
average_two= grouped_two.mean()
print(average_two)
print('\n')
print(type(average_two))

#결과값
                     age        fare  survived
class  sex                                    
First  female  34.611765  106.125798  0.968085
       male    41.281386   67.226127  0.368852
Second female  28.722973   21.970121  0.921053
       male    30.740707   19.741782  0.157407
Third  female  21.750000   16.118810  0.500000
       male    26.507589   12.661633  0.135447
#개별 그룹 선택하기
group3f= grouped_two.get_group(('Third', 'female'))

 

5-2 그룹 연산 메소드(적용-결합 단계)

  • 데이터집계

앞에서 분할한 그룹 객체에 각 그룹별 평균을 계산한 것처럼, 그룹 객체에 다양한 연산을 적용할 수 있다.

#집계 기본 함수종류
min(), mean(), max(), min(), sum(), count(), size(),var(), describe(), info(), first(), last()

#표준편차 데이터 집계
group.std()
import pandas as pd
import seaborn as sns

#titanic 데이터셋에서 age, sex 등 5개의 열을 선택하여 데이터프레임 만들기
titanic= sns.load_dataset('titanic')
df= titanic.loc[:, ['age', 'class', 'fare', 'survived']]

#class 열을 기준으로 분할
grouped= df.groupby(['class'])

#각 그룹에 대한 모든 열의 표준편차를 집계하여 데이터프레임으로 변환
std_all= grouped.std()
print(std_all)
print('\n')

#각 그룹에 대한 fare 열의 표준편차를 집계하여 시리즈로 반환
std_fare= grouped.fare.std()
print(std_fare)

#결과값
              age       fare  survived
class                                 
First   14.802856  78.380373  0.484026
Second  14.001077  13.417399  0.500623
Third   12.495398  11.778142  0.428949


class
First     78.380373
Second    13.417399
Third     11.778142
Name: fare, dtype: float64

 

사용자 정의함수를 그룹 객체에 적용하려면 agg() 메소드를 사용한다.

agg()메소드 데이터 집계
group.agg(매핑 함수)
#그룹 객체에 agg()메소드 적용- 사용자 정의 함수를 인자로 전달
def min_max(x): #최대값- 최소값
    return x.max() - x.min()

#각 그룹의 최대값과 최소값의 차이를 계산하여 그룹별로 집계
agg_minmax= grouped.agg(min_max)
print(agg_minmax.head())

#결과값
          age      fare  survived
class                            
First   79.08  512.3292         1
Second  69.33   73.5000         1
Third   73.58   69.5500         1

 

동시에 여러 개의 함수를 사용하여 각 그룹별 데이터에 대한 집계 연산을 처리할 수 있다. 각각의 열에 여러 개의 함수를 일괄 적용할 때는 리스트 형태로 인수를 전달하고, 열마다 다른 종류의 함수를 적용하려면 {열:함수} 형태의 딕셔너리를 전달한다.

# 모든 열에 여러 함수를 매핑
group객체.agg([함수1, 함수2, 함수3, ...]) # 인수는 리스트 형태

# 각 열마다 다른 함수를 매핑
group객체.agg({'열1' : 함수1, '열2' : 함수2, ...}) # 인수는 딕셔너리 형태

>> 예시
# 여러 함수를 각 열에 동일하게 적용하여 집계
agg_all = grouped.agg(['min','max'])

# 각 열마다 다른 함수를 적용하여 집계
agg_sep = grouped.agg({'fare':['min','max'], 'age':'mean'})
         age       fare           survived    
         min   max  min       max      min max
class                                         
First   0.92  80.0  0.0  512.3292        0   1
Second  0.67  70.0  0.0   73.5000        0   1
Third   0.42  74.0  0.0   69.5500        0   1
       fare                  age
        min       max       mean
class                           
First   0.0  512.3292  38.233441
Second  0.0   73.5000  29.877630
Third   0.0   69.5500  25.140620

 

  • 그룹 연산 데이터 변환

transform() 메소드는 그룹별로 구분하여 각 원소에 함수를 적용하지만 그룹별 집계 대신 각 원소의 본래 행 인덱스와 열 이름을 기준으로 연산 결과를 반환한다. 즉, 그룹 연산의 결과를 원본 데이터프레임과 같은 형태로 변형하여 정리하는 것.

#데이터 변환 연산
group.transform(매핑 함수)

#그룹 객체의 age 열의 데이터를 z-score 로 변환
group_zscore= grouped.age.transform(z_score)

 

  • 그룹 객체 필터링

그룹 객체에 filter() 메소드를 적용할 때 조건식을 가진 함수를 전달하면 조건이 참인 그룹만을 남긴다

#그룹 객체 필터링
group.filter(조건식 함수)

#데이터 개수가 200개 이상인 그룹만을 필터링하여 데이터프레임으로 변환
grouped_filter = grouped.filter(lambda x: len(x) >= 200)

#결과값
    age  class     fare  survived
0  22.0  Third   7.2500         0
1  38.0  First  71.2833         1
2  26.0  Third   7.9250         1
3  35.0  First  53.1000         1
4  35.0  Third   8.0500         0

 

  • 그룹 객체에 함수 매핑

apply() 메소드는 판다스 객체의 개별 원소를 특정 함수에 일대일로 매핑한다. 사용자가 원하는 대부분의 연산을 그룹 객체에도 적용할 수 있다.

#범용 메소드
group.apply(매핑함수)
#집계: 각 그룹별 요약 통계 정보 집계
agg_grouped= grouped.apply(lambda x: x.describe()) 	#요약 통계정보를 위해 describe() 메소드 적용

 

6. 멀티 인덱스

행 인덱스를 여러 레벨로 구현할 수 있도록 멀티 인덱스 클래스를 지원한다.

import pandas as pd
import seaborn as sns

#titanic 데이터셋에서 age, sex 등 5개의 열을 선택하여 데이터프레임 만들기
titanic= sns.load_dataset('titanic')
df= titanic.loc[:, ['age', 'sex', 'class', 'fare', 'survived']]

#class 열을 기준으로 분할
grouped= df.groupby(['class', 'sex'])

#그룹 객체에 연산 메소드 적용
gdf= grouped.mean()
print(gdf)
print('\n')
print(type(gdf))


#결과값

                     age        fare  survived
class  sex                                    
First  female  34.611765  106.125798  0.968085
       male    41.281386   67.226127  0.368852
Second female  28.722973   21.970121  0.921053
       male    30.740707   19.741782  0.157407
Third  female  21.750000   16.118810  0.500000
       male    26.507589   12.661633  0.135447
#멀티 인덱스에서 하나의 인덱스만 사용하는 방법
print(gdf.loc['First'])

# 멀티 인덱스에서 두 개의 인덱스 사용 - First이면서 female인 행 선택 (튜플 인자)
print(gdf.loc[('First','female'])

# xs인덱서 - 'sex' 인덱스에서 'male'
gdf.xs('male', level='sex))

 

7. 피벗

피벗테이블을 구성하는 4가지 요소(행 인덱스, 열 인덱스, 데이터 값, 데이터 집계 함수)에 적용할 데이터프레임의 열을 각각 지정하여 함수의 인자로 전달한다.

# 데이터프레임의 형태를 피벗테이블로 변환
pivot_table()

 

import pandas as pd
import seaborn as sns

#titanic 데이터셋에서 age, sex 등 5개의 열을 선택하여 데이터프레임 만들기
titanic= sns.load_dataset('titanic')
df= titanic.loc[:, ['age', 'sex', 'class', 'fare', 'survived']]

# 행, 열, 값, 집계에 사용할 열을 1개씩 지정 - 평균 집계
pdf1 = pd.pivot_table(df,				# 피벗할 데이터프레임
                      index='class',			# 행 위치에 들어갈 열
                      columns='sex',   			# 열 위치에 들어갈 열
                      values='age',     		# 데이터로 사용할 열
                      aggfunc='mean')   		# 데이터 집계 함수

#결과값
sex        female       male
class                       
First   34.611765  41.281386
Second  28.722973  30.740707
Third   21.750000  26.507589
#여려개의 값 지정도 가능하다
import pandas as pd
import seaborn as sns

#titanic 데이터셋에서 age, sex 등 5개의 열을 선택하여 데이터프레임 만들기
titanic= sns.load_dataset('titanic')
df= titanic.loc[:, ['age', 'sex', 'class', 'fare', 'survived']]

# 행, 열, 값, 집계에 사용할 열을 1개씩 지정 - 평균 집계
pdf3 = pd.pivot_table(df,						# 피벗할 데이터프레임
                      index=['class', 'sex'],    # 행 위치에 들어갈 열
                      columns='survived',   			# 열 위치에 들어갈 열
                      values=['age', 'fare'],     		# 데이터로 사용할 열
                      aggfunc=['mean', 'max'])   		# 데이터 집계 함수

print(pdf3.head())

#결과값
                    mean                                      max        \
                     age                   fare               age         
survived               0          1           0           1     0     1   
class  sex                                                                
First  female  25.666667  34.939024  110.604167  105.978159  50.0  63.0   
       male    44.581967  36.248000   62.894910   74.637320  71.0  80.0   
Second female  36.000000  28.080882   18.250000   22.288989  57.0  55.0   
       male    33.369048  16.022000   19.488965   21.095100  70.0  62.0   
Third  female  23.818182  19.329787   19.773093   12.464526  48.0  63.0   

                                 
                 fare            
survived            0         1  
class  sex                       
First  female  151.55  512.3292  
       male    263.00  512.3292  
Second female   26.00   65.0000  
       male     73.50   39.0000  
Third  female   69.55   31.3875
# 행 인덱스를 2개로 가져오기 -> 투플
print(pdf.xs(('First', 'female')))	#행 인덱스가 first, female 인 행을 선택

#행 인덱스 레벨을 직접 지정하기
print(pdf3.xs('male', level='sex'))	#행 인덱스의 sex 레벨이 male 인 행을 선택

#xs 인덱서 사용- 열 선택(axis=1설정)
print(pdf3.xs('mean', axis=1))	#열 인덱스가 mean인 데이터를 선택