-
[ML-2] 파이썬 _ 판다스(Pandas) 패키지머신러닝 2022. 1. 11. 23:24
- 판다스(Pandas) : 행과 열로 구성된 2차원 데이터를 효율적으로 가공 및 처리할 수 있는 패키지
- 데이터프레임(DataFrame) : 판다스(Pandas)의 핵심 객체 / 여러 개의 행과 열로 이뤄진 2차원 데이터를 담는 데이터 구조체 / 칼럼(column)이 여러 개인 데이터 구조체
import pandas as pd # pandas를 pd로 alias해 임포트하는 것이 관례
여기서 데이터셋은 캐글(Kaggle)에서 제공하는 타이타닉 탑승자 파일을 사용한다.
캐글에서 다운 받은 'titanic_train.csv' 파일을 사용하는데 여기서 확장자 '.csv'는 칼럼(Column)들이 ','로 구분되어 있는 파일 포맷을 얘기한다. 다운 받은 데이터를 보면 아래와 같이 ','로 구분되어 있는 있는 것을 확인할 수 있다.
해당 데이터를 판다스 API를 이용하여 불러오게 되면 데이터셋은 데이터프레임 객체로 존재하게 된다.
titanic_df=pd.read_csv('titanic_train.csv')#read_csv() API는 csv포맷의 파일을 DataFrame 객체로 가져오게 함 print(titanic_df) [결과] PassengerId Survived Pclass ... Fare Cabin Embarked 0 1 0 3 ... 7.2500 NaN S 1 2 1 1 ... 71.2833 C85 C 2 3 1 3 ... 7.9250 NaN S 3 4 1 1 ... 53.1000 C123 S 4 5 0 3 ... 8.0500 NaN S .. ... ... ... ... ... ... ...
.csv의 데이터셋이 DataFrame으로 변경된 것을 확인할 수 있다.
각각의 칼럼을 제외하고 칼럼명이 명시되어 있지 않은 데이터는 Index다. 모든 DataFrame 내의 데이터는 생성되는 순간 고유의 Index 값을 가지게 된다.
print('titanic_df의 크기 : ', titanic_df.shape) # shape 변수는 DataFrame의 행과 열을 튜플 형태로 반환함 [결과] titanic_df의 크기 : (891, 12) # 891개의 row와 12개의 col로 구성
value_counts=titanic_df['Pclass'].value_counts() """ DataFrame의 []내부에 칼럼명을 입력하면 Series 형태로 특정 칼럼 데이터셋이 반환됨 value_counts() 메서드는 데이터의 분포를 확인하는 함수 호출 시 해당 칼럼값의 유형과 건수를 확인할 수 있음 """ print(value_counts) [결과] 3 491 1 216 2 184 """ 칼럼 'Pclass'는 3,1,2를 가지고 3이 491개, 1이 216개, 2가 184개 있음 value_counts() 메서드는 많은 건수 순서로 정렬되어 반환함 """
[ndarray,리스트,딕셔너리를 DataFrame으로 변환]
DataFrame은 리스트,ndarray와는 달리 칼럼명을 가지고 있다. 따라서 칼럼명을 지정해서 변환해주어야 한다(지정하지 않으면 자동으로 칼럼명을 할당함).
""" 1차원 리스트, ndarry """ col_name1=['col1'] # 칼럼명 지정 list1=[1,2,3] # 리스트 array1=np.array(list1) # ndarray df_list1=pd.DataFrame(list1,columns=col_name1) # 리스트 -> DataFrame print('리스트로 만든 DataFrame:\n',df_list1) df_array1=pd.DataFrame(array1,columns=col_name1) # ndarray -> DataFrame print('ndarray로 만든 DataFrame:\n',df_array1) [결과] 리스트로 만든 DataFrame: col1 0 1 1 2 2 3 ndarray로 만든 DataFrame: col1 0 1 1 2 2 3 """ 2차원 리스트, ndarray DataFrame은 2차원 데이터이므로 2차원 이하의 데이터들만 변환 가능 """ col_name2=['col1','col2','col3'] # 칼럼명 지정 list2=[[1,2,3], [11,12,13]] # 2차원 리스트 array2=np.array(list2) # 2차원 ndarray df_list2=pd.DataFrame(list2,columns=col_name2) # 2차원 리스트 -> DataFrame print('2차원 리스트로 만든 DataFrame:\n',df_list2) df_array2=pd.DataFrame(array2,columns=col_name2) # 2차원 ndarray -> DataFrame print('2차원 ndarray로 만든 DataFrame:\n',df_array2) [결과] 2차원 리스트로 만든 DataFrame: col1 col2 col3 0 1 2 3 1 11 12 13 2차원 ndarray로 만든 DataFrame: col1 col2 col3 0 1 2 3 1 11 12 13 """ 딕셔너리를 DataFrame으로 변환 딕셔너리의 Key -> Col 딕셔너리의 Value -> Data """ dict={'col1':[1,11],'col2':[2,22],'col3':[3,33]} df_dict=pd.DataFrame(dict) # 딕셔너리 -> DataFrame print('딕셔너리로 만든 DataFrame:\n',df_dict) [결과] 딕셔너리로 만든 DataFrame: col1 col2 col3 0 1 2 3 1 11 22 33
[DataFrame을 ndarray,리스트,딕셔너리로 변환]
머신러닝 패키지에서 기본 데이터 형으로 ndarray를 사용한다. 따라서 DataFrame을 ndarray로 변환하는 경우가 빈번하게 발생한다.
array3=df_dict.values # values를 이용하면 간단하게 ndarray로 변환 print('DataFrame을 ndarray로 변환:\n',array3) [결과] [[ 1 2 3] [11 22 33]] """ 리스트로의 변환은 values로 얻은 ndarray에 .tolist() 호출 딕셔너리로의 변환은 DataFrame 객체의 to_dict() 메서드 호출, 인자로 'list'입력 시 딕셔너리의 값은 리스트형으로 반환 """ list3=df_dict.values.tolist() # list3=array3.tolist() print('DataFrame을 리스트로 변환:\n',list3) dict3=df_dict.to_dict('list') print('DataFrame을 딕셔너리로 변환:\n',dict3) [결과] DataFrame을 리스트로 변환: [[1, 2, 3], [11, 22, 33]] DataFrame을 딕셔너리로 변환: {'col1': [1, 11], 'col2': [2, 22], 'col3': [3, 33]}
[DataFrame 데이터 관리]
""" 칼럼 데이터 생성 및 수정 """ titanic_df['new col']=0 # 새로운 칼럼 'new col'을 추가하고 일괄적으로 0 값 할당 print(titanic_df) [결과] PassengerId Survived Pclass ... Cabin Embarked new col 0 1 0 3 ... NaN S 0 1 2 1 1 ... C85 C 0 2 3 1 3 ... NaN S 0 3 4 1 1 ... C123 S 0 4 5 0 3 ... NaN S 0 .. ... ... ... ... ... ... ... """ 새로운 Series가 기존 DataFrame에 추가되는 것 따라서 기존 칼럼의 Series의 데이터를 이용하여 새로운 칼럼도 만들 수 있음 """ titanic_df['new col2']=titanic_df['new col']+100 print(titanic_df) [결과] PassengerId Survived Pclass ... Embarked new col new col2 0 1 0 3 ... S 0 100 1 2 1 1 ... C 0 100 2 3 1 3 ... S 0 100 3 4 1 1 ... S 0 100 4 5 0 3 ... S 0 100 .. ... ... ... ... ... ... ... """ 수정 또한 같은 방법으로 할 수 있음 """ titanic_df['new col2']+=100 print(titanic_df) [결과] PassengerId Survived Pclass ... Embarked new col new col2 0 1 0 3 ... S 0 200 1 2 1 1 ... C 0 200 2 3 1 3 ... S 0 200 3 4 1 1 ... S 0 200 4 5 0 3 ... S 0 200 .. ... ... ... ... ... ... ... """ DataFrame 데이터 삭제 drop() 메서드 활용 drop() 메서드의 원형 DataFrame.drop(labels=None, axis=0, index=None, Columns=None, level=None, inplace=False, errors='raise') axis의 값에 따라서 칼럼 또는 행을 삭제함(axis=0 -> row , axis=1 -> col) label에는 원하는 칼럼명 입력 """ titanic_df_drop=titanic_df.drop('new col2',axis=1) # 'new col2' 칼럼을 드롭 print(titanic_df_drop) [결과] PassengerId Survived Pclass ... Cabin Embarked new col 0 1 0 3 ... NaN S 0 1 2 1 1 ... C85 C 0 2 3 1 3 ... NaN S 0 3 4 1 1 ... C123 S 0 4 5 0 3 ... NaN S 0 .. ... ... ... ... ... ... ... """ 하지만 'new col2' 칼럼을 드롭한 후에 원본 데이터셋을 보면 여전히 'new col2' 칼럼이 존재하는 것을 볼 수 있음 """ print(titanic_df) [결과] PassengerId Survived Pclass ... Embarked new col new col2 0 1 0 3 ... S 0 200 1 2 1 1 ... C 0 200 2 3 1 3 ... S 0 200 3 4 1 1 ... S 0 200 4 5 0 3 ... S 0 200 """ 원본 데이터셋 자체를 삭제하고 싶다면 inplece=True 로 설정해주어야 함(inplace의 디폴트 값은 False) """ titanic_df.drop('new col2',axis=1,inplace=True) # inplace=True 입력 시 반환x print(titanic_df) [결과] # 원본 데이터에서도 삭제됨을 확인할 수 있음 PassengerId Survived Pclass ... Cabin Embarked new col 0 1 0 3 ... NaN S 0 1 2 1 1 ... C85 C 0 2 3 1 3 ... NaN S 0 3 4 1 1 ... C123 S 0 4 5 0 3 ... NaN S 0 .. ... ... ... ... ... ... ...
[데이터 셀렉션 및 필터링]
DataFrame 뒤의 '[]'는 칼럼만 지정할 수 있는 '칼럼 지정 연산자'로 이해하는 것이 좋다.
ix[] 연산자는 코드에 혼돈을 주거나 가독성을 떨어지게 하기 때문에 대신 loc[] 연산자와 iloc[] 연산자를 사용한다.
loc[] 연산자와 iloc[] 연산자를 살펴보기 이전에
'명칭 기반 인덱싱'과 '위치 기반 익덱싱'을 구분해야 한다.
'명칭(Label) 기반 인덱싱'은 칼럼의 명칭을 기반으로 위치를 지정하는 방식을 말한다.
'위치(Position) 기반 인덱싱'은 0을 출발점으로 하는 가로축, 세로축 좌표 기반의 행/열 위치를 기반으로 지정하는 방식을 말한다.
DataFrame의 익덱스 값은 '명칭(Label) 기반 인덱싱'으로 간주해야 한다.
1. iloc 연산자 : 위치 기반 인덱싱, int형, int형 슬라이싱, 팬시 리스트 값 입력
""" PassengerId Survived Pclass ... Fare Cabin Embarked 0 1 0 3 ... 7.2500 NaN S 1 2 1 1 ... 71.2833 C85 C 2 3 1 3 ... 7.9250 NaN S 3 4 1 1 ... 53.1000 C123 S 4 5 0 3 ... 8.0500 NaN S .. ... ... ... ... ... ... ... 886 887 0 2 ... 13.0000 NaN S 887 888 1 1 ... 30.0000 B42 S 888 889 0 3 ... 23.4500 NaN S 889 890 1 1 ... 30.0000 C148 C 890 891 0 3 ... 7.7500 NaN Q """ print(titanic_df.iloc[0,2]) # 첫번째 행의 3번째 열 값 출력 print('----') print(titanic_df.iloc[:5,2]) # 첫번째 행 ~ 5번째 행의 3번째 열 값 출력 [결과] 3 ---- 0 3 1 1 2 3 3 1 4 3
2. loc[] 연산자 : 명칭 기반 인덱싱, loc[index 값,칼럼 명]
""" PassengerId Survived Pclass ... Fare Cabin Embarked 0 1 0 3 ... 7.2500 NaN S 1 2 1 1 ... 71.2833 C85 C 2 3 1 3 ... 7.9250 NaN S 3 4 1 1 ... 53.1000 C123 S 4 5 0 3 ... 8.0500 NaN S .. ... ... ... ... ... ... ... 886 887 0 2 ... 13.0000 NaN S 887 888 1 1 ... 30.0000 B42 S 888 889 0 3 ... 23.4500 NaN S 889 890 1 1 ... 30.0000 C148 C 890 891 0 3 ... 7.7500 NaN Q """ print(titanic_df.loc[0,'Embarked']) print('----') print(titanic_df.loc[1:5,'Cabin']) [결과] S ---- 1 C85 2 NaN 3 C123 4 NaN 5 NaN """ loc[] 연산자는 '명칭 기반 인덱싱' 이므로 슬라이싱 범위를 [1:5]로 입력했을 때 1,2,3,4,5 index 가 출력되는 것을 인지해야 함. '위치 기반 인덱싱' iloc[] 연산자였다면 1,2,3,4 index가 출력 이 둘의 차이를 이해할 필요가 있음 "명칭 기반 인덱싱"은 슬라이싱을 '시작점:종료점'으로 지정할 때 시작점에서 종료점을 포함한 위치에 있는 데이터를 반환하는구나" """
3. 불린 인덱싱
""" PassengerId Survived Pclass ... Fare Cabin Embarked 0 1 0 3 ... 7.2500 NaN S 1 2 1 1 ... 71.2833 C85 C 2 3 1 3 ... 7.9250 NaN S 3 4 1 1 ... 53.1000 C123 S 4 5 0 3 ... 8.0500 NaN S .. ... ... ... ... ... ... ... 886 887 0 2 ... 13.0000 NaN S 887 888 1 1 ... 30.0000 B42 S 888 889 0 3 ... 23.4500 NaN S 889 890 1 1 ... 30.0000 C148 C 890 891 0 3 ... 7.7500 NaN Q """ print(titanic_df[titanic_df['Age']>60]) # 'Age' 칼럼 값이 60 보다 큰 데이터를 모두 반환 [결과] PassengerId Survived Pclass ... Fare Cabin Embarked 33 34 0 2 ... 10.5000 NaN S 54 55 0 1 ... 61.9792 B30 C 96 97 0 1 ... 34.6542 A5 C 116 117 0 3 ... 7.7500 NaN Q 170 171 0 1 ... 33.5000 B19 S 252 253 0 1 ... 26.5500 C87 S 275 276 1 1 ... 77.9583 D7 S 280 281 0 3 ... 7.7500 NaN Q 326 327 0 3 ... 6.2375 NaN S 438 439 0 1 ... 263.0000 C23 C25 C27 S 456 457 0 1 ... 26.5500 E38 S 483 484 1 3 ... 9.5875 NaN S 493 494 0 1 ... 49.5042 NaN C 545 546 0 1 ... 26.0000 NaN S 555 556 0 1 ... 26.5500 NaN S 570 571 1 2 ... 10.5000 NaN S 625 626 0 1 ... 32.3208 D50 S 630 631 1 1 ... 30.0000 A23 S 672 673 0 2 ... 10.5000 NaN S 745 746 0 1 ... 71.0000 B22 S 829 830 1 1 ... 80.0000 B28 NaN 851 852 0 3 ... 7.7750 NaN S print(titanic_df.loc[titanic_df['Age']>60,['Name','Age']]) #'Age' 칼럼 값이 60보다 큰 데이터 중에서 'Name','Age' 칼럼만 반환 [결과] Name Age 33 Wheadon, Mr. Edward H 66.0 54 Ostby, Mr. Engelhart Cornelius 65.0 96 Goldschmidt, Mr. George B 71.0 116 Connors, Mr. Patrick 70.5 170 Van der hoef, Mr. Wyckoff 61.0 252 Stead, Mr. William Thomas 62.0 275 Andrews, Miss. Kornelia Theodosia 63.0 280 Duane, Mr. Frank 65.0 326 Nysveen, Mr. Johan Hansen 61.0 438 Fortune, Mr. Mark 64.0 456 Millet, Mr. Francis Davis 65.0 483 Turkula, Mrs. (Hedwig) 63.0 493 Artagaveytia, Mr. Ramon 71.0 545 Nicholson, Mr. Arthur Ernest 64.0 555 Wright, Mr. George 62.0 570 Harris, Mr. George 62.0 625 Sutton, Mr. Frederick 61.0 630 Barkworth, Mr. Algernon Henry Wilson 80.0 672 Mitchell, Mr. Henry Michael 70.0 745 Crosby, Capt. Edward Gifford 70.0 829 Stone, Mrs. George Nelson (Martha Evelyn) 62.0 851 Svensson, Mr. Johan 74.0 print(titanic_df[(titanic_df['Age']>60)&(titanic_df['Pclass']==1) &(titanic_df['Sex']=='female')]) # 60세 이상의 선실 등급 1등극인 승객 중 여성 승객만 추출(복합 조건 연산자 사용) [결과] PassengerId Survived Pclass ... Fare Cabin Embarked 275 276 1 1 ... 77.9583 D7 S 829 830 1 1 ... 80.0000 B28 NaN
[정렬, Aggregation, GroupBy]
1. 정렬 : sort_values()
주요 입력 파라미터로는 by, ascending, inplace가 있다.
by는 특정 칼럼을 입력하면 해당 칼럼으로 정렬을 수행하며, ascending을 디폴트 값이 True(오름차순)이다.
inplace는 앞서 살펴본 바와 같이 디폴트 값이 False이다.
""" PassengerId Survived Pclass ... Fare Cabin Embarked 0 1 0 3 ... 7.2500 NaN S 1 2 1 1 ... 71.2833 C85 C 2 3 1 3 ... 7.9250 NaN S 3 4 1 1 ... 53.1000 C123 S 4 5 0 3 ... 8.0500 NaN S .. ... ... ... ... ... ... ... 886 887 0 2 ... 13.0000 NaN S 887 888 1 1 ... 30.0000 B42 S 888 889 0 3 ... 23.4500 NaN S 889 890 1 1 ... 30.0000 C148 C 890 891 0 3 ... 7.7500 NaN Q """ sort_by_age=titanic_df.sort_values(by=['Age']) # 'Age' 칼럼 기준 오름차순 정렬 print(sort_by_age) [결과] PassengerId Survived Pclass ... Fare Cabin Embarked 803 804 1 3 ... 8.5167 NaN C 755 756 1 2 ... 14.5000 NaN S 644 645 1 3 ... 19.2583 NaN C 469 470 1 3 ... 19.2583 NaN C 78 79 1 2 ... 29.0000 NaN S .. ... ... ... ... ... ... ... 859 860 0 3 ... 7.2292 NaN C 863 864 0 3 ... 69.5500 NaN S 868 869 0 3 ... 9.5000 NaN S 878 879 0 3 ... 7.8958 NaN S 888 889 0 3 ... 23.4500 NaN S
2. aggregation 함수 적용 _ min(), max(), sum(), count()
DataFrame의 경우 DataFrame에 바로 agregation 호출할 경우 모든 칼럼에 적용된다. 따라서 대상 칼럼들만 추출하여 aggregation을 적용해주어야 한다.
print(titanic_df[['Age']].min()) # 'Age' 칼럼의 최소값 [결과] Age 0.42
3. groupby() 적용
DataFrame에 groupby()를 호출하면 DataFrameGroupBy라는 또 다른 형태의 DataFrame을 반환한다.
""" groupby()를 호출해 반환된 결과에 aggregation 함수를 호출할 수 있다 """ titanic_groupby=titanic_df.groupby('Pclass').count() print(titanic_groupby) [결과] PassengerId Survived Name Sex ... Ticket Fare Cabin Embarked Pclass ... 1 216 216 216 216 ... 216 216 176 214 2 184 184 184 184 ... 184 184 16 184 3 491 491 491 491 ... 491 491 12 491 # ------------------------------- titanic_groupby=titanic_df.groupby('Pclass')[['PassengerId','Survived']].count() # 이처럼 DataFrameGroupBy 객체에 [['PassengerId','Survived']]로 특정 칼럼을 필터링하여 aggregation 함수를 적용할 수 있음 print(titanic_groupby) [결과] PassengerId Survived Pclass 1 216 216 2 184 184 3 491 491 # ------------------------------- agg_format={'Age':'max','SibSp':'sum','Fare':'mean'} # 딕셔너리 형태로 agg의 입력 값을 구성 titanic_groupby=titanic_df.groupby('Pclass').agg(agg_format) # 'Pclass'칼럼에 대해, 'Age'칼럼의 최대 값, 'SibSp'칼럼의 총합, 'Fare'칼럼의 평균을 가지는 데이터셋 print(titanic_groupby) [결과] Age SibSp Fare Pclass 1 80.0 90 84.154687 2 70.0 74 20.662183 3 74.0 302 13.675550
4. lambda
lambda 식은 파이썬에서 함수형 프로그래밍을 지원하기 위해 만들어졌다.
아래와 같은 입력값의 제곱 값을 반환하는 get_square(a)라는 함수가 있다고 가정하자.
def get_square(a): return a**2
이러한 함수를 lambda 식으로 변환하면 아래와 같다.
lambda_square=lambda x : x**2 # 입력인자 x에 대해서 x**2 값을 반환
DataFrame에 활용해보면
titanic_df['Name_len']=titanic_df['Name'].apply(lambda x:len(x)) # 'Name'칼럼의 값을 인자로 받아 길이를 'Name_len'칼럼에 저장 print(titanic_df[['Name','Name_len']]) [결과] Name Name_len 0 Braund, Mr. Owen Harris 23 1 Cumings, Mrs. John Bradley (Florence Briggs Th... 51 2 Heikkinen, Miss. Laina 22 3 Futrelle, Mrs. Jacques Heath (Lily May Peel) 44 4 Allen, Mr. William Henry 24 .. ... ... 886 Montvila, Rev. Juozas 21 887 Graham, Miss. Margaret Edith 28 888 Johnston, Miss. Catherine Helen "Carrie" 40 889 Behr, Mr. Karl Howell 21 890 Dooley, Mr. Patrick 19
조건문도 활용할 수 있다.
titanic_df['Child_Adult']=titanic_df['Age'].apply(lambda x:'Child' if x<=15 else 'Adult') # 'Age'칼럼 값을 x로 받아 15보다 작거나 같으면 'Child' 아니면 'Adult' 반환하여 'Child_Adult'칼럼에 저장
여기서 주의해야할 점은 lambda 식 ':' 기호의 오른편에 반환 값이 존재해야 한다는 것이다.
lambda x:if x<=15 'Child' else 'Adult'
위와 같이 작성하면 안된다는 것이다.
'머신러닝' 카테고리의 다른 글
[ML-1] 파이썬 _ 넘파이(Numpy) 패키지 (0) 2022.01.10 [ML-0] 머신러닝이란 (0) 2022.01.10