본문 바로가기

AI Study/Machine Learning

머신러닝을 위한 Pandas 기초

Pandas 기본 개념
 
 
  • 데이터 : 일반적으로 2차원 (row * column)
  • numpy보다 유연하고 편리한 데이터 핸들링
    • numpy의 ndaaray 내의 데이터 타입은 그 연산의 특성상 같은 데이터 타입만 가능함(한 개의 ndarray 객체에 int, float 함께 존재 X)
    • pandas의 DataFrame내에는 column마다 다른 data type이 가능
  • 핵심 객체 : DataFrame(행,열로 구성된 2차원 데이터를 담은 데이터 구조체)
    • Series : 칼럼이 1개뿐인 데이터 구조체
    • DataFrame : 칼럼이 여러 개인 데이터 구조체
    • index : 개별 데이터를 고유하게 식별하는 Key값, Series와 Dataframe 모두 index를 가짐
  • 주로 read_csv(filepath_or buffer, sep=',', ...) 사용 -> csv : comma-separated values. 칼럼을 ','로 구분한 파일 포맷
    • filepath에서 주의할 사항
      • ipynb파일위치 != data위치 : read_csv(r'file path', sep = '..')
      • ipynb파일위치 == data위치 : read_csv('file name', sep = "..")

Q. Why do we have to use 'r' before path-name while using pd.read_csv?

A. In python, backslash is used to signify special character. Pathnames on Windows tend to have backslashes in them. But we want them to mean actual backslashes, not special characters.
'r' stands for 'raw' and will cause backslashes in the string to be interpreted as actual backslashes rather than special character.
 

  • list, dictionary로부터 DataFrame 생성 : pd.DataFrame
    • from list : col_name list생성, 이중list로 value표현
    • from dictionary : key값은 칼럼명, value는 각 칼럼 데이터로 매핑됨

In [36]:
import pandas as pd
 
In [37]:
# list로부터 DataFrame 생성

# 칼럼명이 될 리스트 생성
col_name = ['A','B','C']

# value에 대한 리스트 생성
value_list = [['v1','v2','v3'],
             [1,2,3]]

# DataFrame 생성
df_from_list = pd.DataFrame(data=value_list, columns=col_name)
df_from_list
 
Out[37]:
 
  A B C
0 v1 v2 v3
1 1 2 3
In [38]:
# dictionary로부터 DataFrame 생성

# Key는 문자열 칼럼명으로 매핑, Value는 리스트 형 또는 ndarray 칼럼 데이터로 매핑
dictionary = {'A':['v1',1], 'B':['v2',2], 'C':['v3',3]}
df_from_dict = pd.DataFrame(dictionary)
df_from_dict
 
Out[38]:
 
  A B C
0 v1 v2 v3
1 1 2 3
 

DataFrame 행/열 삭제

  • DataFrame 데이터 삭제 : df.drop()
    • axis = 1 : column 삭제
      • df.drop(['col1','col2',...], axis=1)
    • axis = 0 : row 삭제
    • inplace = True : 원본파괴
    • inplace = False (default) : 새로운 객체로 받아야 함

index와 reset_index

  • DataFrame_name.index or Series_name.index : generator와 같은 상태 (반복문 대상 가능)
    • 리스트 형태로 출력 : df.index.values or series.index.values
  • reset_index() ★★★
    • 새롭게 인덱스를 연속 숫자형으로 할당.
    • inplace=True : 원본 파괴
    • inplace=False(default) : 원본은 유지, 새로운 객체에 할당해야함.
    • drop=True
      • parameter 추가하지 않으면 기존의 index는 'index' 칼럼명을 가진채 칼럼으로 새로 추가됨

In [39]:
df_from_dict.drop('A', axis=1, inplace=True)
df_from_dict
 
Out[39]:
 
 
0 v2 v3
1 2 3

 

In [40]:
df_from_dict.reset_index(inplace=True, drop=False)
df_from_dict
 
Out[40]:
 
  index C  
0 0 v2 v3
1 1 2 3
 

DataFrame의 인덱싱

  • DataFrame의 [ ]연산자
    • DataFrame 바로 뒤의 '[ ]'안에 들어갈 수 있는 것?
      • 칼럼명문자(또는 칼럼 명의 리스트 객체)
        • titanic_df['Pclass']
      • 인덱스로 변환 가능한 표현식(불린 인덱싱)
        • titanic_df[0:2]
        • titanic_df[titanic_df['Sex']=='Female']
  • 명칭기반인덱싱 vs 위치기반인덱싱
    • 명칭기반인덱싱 : 칼럼의 명칭을 기반으로 위치를 지정
      • loc
      • 슬라이싱에서 a:b일 때, b 포함O -> 슬라이싱에서 끝을 포함!
      • loc는 불린 인덱싱 지원 O
    • 위치기반인덱싱 : 0을 출발점으로 하는 가로, 세로의 좌표기반의 행/열 위치로 데이터 지정
      • iloc
      • 슬라이싱에서 a:b일 때, b 포함X
      • iloc는 불린 인덱싱 지원 X
  • df.loc[index, column]

 

In [41]:
df_from_dict.loc[0, 'B']
 
Out[41]:
'v2'
 
In [42]:
df_from_dict.loc[0, ['B','C']]
 
Out[42]:
B    v2
C    v3
Name: 0, dtype: object
 

타이타닉 데이터로 해보는 Pandas 전처리 실습

In [43]:
import pandas as pd
df = pd.read_csv(r'data/titanic_train.csv')
df.head(3)
 
Out[43]:
 
  PassengerId Survived Pclass Name           Sex  Age SibSp Parch Ticket    Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.9250 NaN S
In [44]:
# shape : row, column 크기 파악
df.shape
 
Out[44]:
(891, 12)
 

  • info() / describe() 함수 : 메타 데이터 조회
    • info() : 총 데이터 건수, 데이터 타입, Null 건수 파악
    • describe() : 숫자형 데이터로 된 컬럼에 대해 작동, n-percentile 분포, 평균, 최대최소값 등 개략적인 데이터 분포도 확인
In [45]:
# info
df.info()
 
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 891 entries, 0 to 890
Data columns (total 12 columns):
 #   Column       Non-Null Count  Dtype  
---  ------       --------------  -----  
 0   PassengerId  891 non-null    int64  
 1   Survived     891 non-null    int64  
 2   Pclass       891 non-null    int64  
 3   Name         891 non-null    object 
 4   Sex          891 non-null    object 
 5   Age          714 non-null    float64
 6   SibSp        891 non-null    int64  
 7   Parch        891 non-null    int64  
 8   Ticket       891 non-null    object 
 9   Fare         891 non-null    float64
 10  Cabin        204 non-null    object 
 11  Embarked     889 non-null    object 
dtypes: float64(2), int64(5), object(5)
memory usage: 83.7+ KB
 
In [46]:
# describe
df.describe()
 
Out[46]:
 
  PassengerId Survived     Pclass      Age        SibSp       Parch       Fare       
count 891.000000 891.000000 891.000000 714.000000 891.000000 891.000000 891.000000
mean 446.000000 0.383838 2.308642 29.699118 0.523008 0.381594 32.204208
std 257.353842 0.486592 0.836071 14.526497 1.102743 0.806057 49.693429
min 1.000000 0.000000 1.000000 0.420000 0.000000 0.000000 0.000000
25% 223.500000 0.000000 2.000000 20.125000 0.000000 0.000000 7.910400
50% 446.000000 0.000000 3.000000 28.000000 0.000000 0.000000 14.454200
75% 668.500000 1.000000 3.000000 38.000000 1.000000 0.000000 31.000000
max 891.000000 1.000000 3.000000 80.000000 8.000000 6.000000 512.329200
 

불린 인덱싱 / 복합 조건 연결식

- df[df[컬럼]에 대한 조건][[여러 컬럼들]] -> 컬럼설정 시 이중대괄호 주의
- df.loc[불린식, [컬럼들]]
- 복합 조건 연결식
    - and 조건 : &
    - or 조건 : |
    - Not 조건 : ~
 
In [47]:
df[df['Age']>60][['Fare','Sex','Survived']].head(3) # [[컬럼]] 컬럼 순서도 변환됨 주의!
 
Out[47]:
 
  Fare   Sex   Survived
33 10.5000 male 0
54 61.9792 male 0
96 34.6542 male 0
In [48]:
# 위의 불린 인덱싱을 loc로 표현
df.loc[df['Age']>60, ['Fare','Sex','Survived']].head(3)
 
Out[48]:
 
  Fare   Sex   Survived
33 10.5000 male 0
54 61.9792 male 0
96 34.6542 male 0
In [49]:
# 복합 조건 연결식

# 여러 불린식과 여러 컬럼을 한번에 지정하기

# 1. 불린식에 이중인덱스 적용
df[ (df['Sex']=='male') & (df['Survived']==1) &
       (df['Age']>50) ][['Name','Age','SibSp','Fare']].head(3)
 
Out[49]:
 
  Name                 Age  SibSp Fare
449 Peuchen, Major. Arthur Godfrey 52.0 0 30.5
570 Harris, Mr. George 62.0 0 10.5
587 Frolicher-Stehli, Mr. Maxmillian 60.0 1 79.2
In [50]:
# 2. 불린식을 변수로 받고, 이중인덱스 적용
con1 = df['Sex']=='male'
con2 = df['Survived']==1
con3 = df['Age']>50

df[ con1&con2&con3 ][['Name','Age','SibSp','Fare']].head(3)
 
Out[50]:
 
  Name                  Age  SibSp Fare
449 Peuchen, Major. Arthur Godfrey 52.0 0 30.5
570 Harris, Mr. George 62.0 0 10.5
587 Frolicher-Stehli, Mr. Maxmillian 60.0 1 79.2
In [51]:
# 3. ★ 불린식을 변수로 받고, loc 활용
df.loc[ con1&con2&con3, ['Name','Age','SibSp','Fare'] ].head(3)
 
Out[51]:
 
  Name                 Age  SibSp Fare
449 Peuchen, Major. Arthur Godfrey 52.0 0 30.5
570 Harris, Mr. George 62.0 0 10.5
587 Frolicher-Stehli, Mr. Maxmillian 60.0 1 79.2

정렬, Aggregation 함수, GroupBy 적용

  • DataFrame, Series의 정렬 : sort_values()
    • value_counts()는 series만 됨. sort_values()는 DataFrame도 됨
    • 주요 파라미터 : by, ascending, inplace
      • by 특정칼럼 : 정렬기준
      • ascending=True(default) : 오름차순
      • ascending=False : 내림차순
      • inplace=False(default) : 원본 유지, 새로운 객체 할당 필요
      • inplace=True : 원본파괴
  • Aggregation 함수 적용
    • min(), max(), sum(), count() ... 등등
    • DataFrame에서 바로 agg함수 호출 시 : 모든 칼럼에 agg 적용
    • 특정 컬럼 적용 원하면 먼저 컬럼 추출 -> 뒤이어 agg 적용
      • ex)df['Age','Pclass'].mean()
In [52]:
# sort_values
df_sorted = df.sort_values(by=['Name'])[['Name','Sex','Age','Pclass']]
df_sorted.head(5)
 
Out[52]:
 
  Name                        Sex     Age   Pclass
845 Abbing, Mr. Anthony male 42.0 3
746 Abbott, Mr. Rossmore Edward male 16.0 3
279 Abbott, Mrs. Stanton (Rosa Hunt) female 35.0 3
308 Abelson, Mr. Samuel male 30.0 2
874 Abelson, Mrs. Samuel (Hannah Wizosky) female 28.0 2
In [53]:
# sort_values
df_sorted2 = df.sort_values(by=['Pclass','Name'], ascending=False)[['Name','Sex','Age','Pclass']]
df_sorted2.head(5)
 
Out[53]:
 
  Name                             Sex    Age  Pclass
868 van Melkebeke, Mr. Philemon male NaN 3
153 van Billiard, Mr. Austin Blyler male 40.5 3
282 de Pelsmaeker, Mr. Alfons male 16.0 3
286 de Mulder, Mr. Theodore male 30.0 3
559 de Messemaeker, Mrs. Guillaume Joseph (Emma) female 36.0 3
In [54]:
# Aggregation 함수 적용
df[['Age','Fare']].mean()
 
Out[54]:
Age     29.699118
Fare    32.204208
dtype: float64
 

groupby() 적용

  • matplotlib 등 그림 그리기 전에 많이 사용함
  • by에 칼럼을 입력하면 대상 칼럼으로 groupby됨
  • DataFrame에 groupby()를 호출하면 DataFrameGroupBy라는 또 다른 형태의 DataFrame 반환
  • agg 함수 적용하지 않으면 generator의 상태와 비슷하게..형태 바로 확인할 수 없음
  • DataFrame의 groupby()에 특정칼럼만 agg를 반영하려면?
    • 1.groupby먼저 적용
    • 2.[ 컬럼 ] 추출 덧붙이기 -> 여러개의 컬럼일 경우 이중대괄호 주의!
    • 3.agg 최종 적용
    • ex) train.groupby(by='Pclass')[['Age','Fare']].mean()
In [55]:
df_group = df.groupby('Pclass').count()
df_group.head(3)
 
Out[55]:
 
  PassengerId Survived Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
Pclass                      
1 216 216 216 216 186 216 216 216 216 176 214
2 184 184 184 184 173 184 184 184 184 16 184
3 491 491 491 491 355 491 491 491 491 12 491
In [56]:
df_group_some = df.groupby('Pclass')[['PassengerId','Survived']].count()
df_group_some
 
Out[56]:
 
  PassengerId Survived
Pclass    
1 216 216
2 184 184
3 491 491
In [57]:
df_group_2 = df.groupby(['Pclass','Sex'])[['PassengerId','Survived']].count()
df_group_2
 
Out[57]:
 
    PassengerId Survived
Pclass Sex    
1 female 94 94
male 122 122
2 female 76 76
male 108 108
3 female 144 144
male 347 347
 

groupby에서 컬럼별로 다른 agg 적용하기!

  • agg()의 입력 값으로 dictionary mapping을 사용
  • 컬럼 : agg함수 로 매칭시킴
In [58]:
agg_format = {'Age':'max', 'SibSp':'sum', 'Fare':'mean'}
df.groupby('Pclass').agg(agg_format)
 
Out[58]:
 
  Age  SibSp Fare    
Pclass      
1 80.0 90 84.154687
2 70.0 74 20.662183
3 74.0 302 13.675550

결손 데이터 처리

  • 결손데이터(Missing Data) : 칼럼에 값이 없는, 즉 NULL인 경우를 의미, numpy의 NaN으로 표시
  • 결손데이터를 채우는 과정이 중요한 이유
    • 머신러닝은 기본적으로 이 NaN값을 처리 하지 않음
    • NaN 값은 평균, 총합 등의 함수 연산 시 제외됨
  • NaN여부 확인 API : isna(), isnull()
    • 모든 칼럼의 값이 NaN인지 아닌지를 True or False로 알려줌
    • sum()과 함께 사용함
      • True(Null이면) = 1
      • False(Not Null이면) = 0
  • NaN 값을 대체하는 (채우는) API : fillna()
    • inplace=True : 원본파괴
    • inplace=False(default) : 원본 비파괴, 새로운 객체에 할당 필요
In [59]:
# isna() or isnull()로 결손 데이터 여부 확인
df.isna().head(3)
 
Out[59]:
 
  PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 False False False False False False False False False False True False
1 False False False False False False False False False False False False
2 False False False False False False False False False False True False
In [60]:
# isna()/isnull() and sum()
df.isnull().sum() # 결측치의 개수만 확인 가능
 
Out[60]:
PassengerId      0
Survived         0
Pclass           0
Name             0
Sex              0
Age            177
SibSp            0
Parch            0
Ticket           0
Fare             0
Cabin          687
Embarked         2
dtype: int64
 
In [61]:
# 'Cabin'칼럼의 결측치는 'C000'으로 채우기
# 'Age'칼럼의 결측치는 'Age'칼럼의 평균값으로 채우기
# 'Embarked'칼럼의 결측치는 'S'로 채우기

df['Cabin'].fillna('C000', inplace=True)
df['Age'].fillna(df['Age'].mean(), inplace=True)
df['Embarked'].fillna('S',inplace=True)
df.isnull().sum()
 
Out[61]:
PassengerId    0
Survived       0
Pclass         0
Name           0
Sex            0
Age            0
SibSp          0
Parch          0
Ticket         0
Fare           0
Cabin          0
Embarked       0
dtype: int64
 

apply lambda로 데이터 가공

  • apply함수에 lambda식을 결합해 DataFrame이나 Series의 레코드별로 데이터를 가공
  • pandas의 경우 칼럼에 일괄적으로 데이터 가공을 하는 것이 속도는 더 빠름
  • 복잡한 데이터 가공이 필요한 경우에 apply lambda 사용
    • lambda 입력인자 : 입력인자를 기반으로 한 계산식
    • ex) lambda x : x ** 2
  • lambda 식을 이용할 때, 여러 개의 값을 입력 인자로 사용해야 할 경우? map()함수를 결합!
    • ex)
    • a = [1,2,3]
    • squares = map(lambda x:x**2, a)
    • list(squares) # squares까지만 하면 class 'map' 상태임
    • 결과 : [1,4,9]
In [62]:
df['Name_len'] = df['Name'].apply(lambda x:len(x)) # ['Name']칼럼의 각 value가 x에 들어감
df[['Name','Name_len']].head(3)
 
Out[62]:
 
  Name                             Name_len
0 Braund, Mr. Owen Harris 23
1 Cumings, Mrs. John Bradley (Florence Briggs Th... 51
2 Heikkinen, Miss. Laina 22

lambda와 if else 절 복합 사용

In [63]:
df['Child_Adult'] = df['Age'].apply(lambda x:'Child' if x<=15 else 'Adult')
df[['Age','Child_Adult']].head(8)
 
Out[63]:
 
  Age     Child_Adult
0 22.000000 Adult
1 38.000000 Adult
2 26.000000 Adult
3 35.000000 Adult
4 35.000000 Adult
5 29.699118 Adult
6 54.000000 Adult
7 2.000000 Child
 

lambda 안에 if else가 두 번 이상 등장할 경우에는 별도의 함수를 만드는 것이 편리

In [64]:
# 나이에 따라 세분화된 분류를 수행하는 함수
def get_category(age):
    cat=''
    if age <= 5: cat = 'Baby'
    elif age <= 12: cat = 'Child'
    elif age <= 18: cat = 'Teenager'
    elif age <= 25: cat = 'Student'
    elif age <= 35: cat = 'Young Adult'
    elif age <= 60: cat = 'Adult'
    else: cat = 'Elderly'
    
    return cat
# lambda식에 위에서 생성한 get_category() 함수를 반환 값으로 지정
# get_category(x)는 입력값으로 'Age'칼럼 값을 받아서 해당하는 cat 반환

df['Age_cat'] = df['Age'].apply(lambda x:get_category(x))
df[['Age','Age_cat']].head()
 
Out[64]:
 
  Age   Age_cat    
0 22.0 Student
1 38.0 Adult
2 26.0 Young Adult
3 35.0 Young Adult
4 35.0 Young Adult

 

 

* 출처 *

파이썬 머신러닝 완벽가이드