쉬운 듯 하면서도 해도해도 모자라고 헷갈리는 것이 판다스 문법이지만 계속해서 시행착오를 거치고 연습하다보면 익숙해 질 것이라 생각한다.
판다스는 사이킷런이라는 머신러닝 알고리즘을 적용하기 전에 데이터의 특성과 상관 관계를 파악하고 빠진 데이터를 처리하는 등 데이터를 분석하고 전처리하는 데 필수적인 툴인 만큼 몇 가지 놓치면 아쉬운 조작법을 몇 가지 더 소개하고자 한다.
물론 지금까지 소개한 내용 이외 판다스를 사용하면서 알아야 두어야 할 사용법들이 더 많겠지만 일단 기본을 바탕으로 조금씩 더 익숙해지고 더 배워나가면 좋을 것 같다.
연습에서는 손댈 게 별로 없는 데이터가 많겠지만 현실에서는 아예 없거나 빠져있는 데이터가 더 많을 것이다. 게다가 누구나 배워서 사용할 수 있는 게 머신러닝 라이브러리라면 그 만큼 그에 맞는 데이터를 수집, 정리, 보강해서 사용하는 것이 무엇보다 중요하다고 할 수 있다. (물론 알고리즘 파라미터의 수정이나 앙상블 기법 등을 통해 머신러닝의 정확도를 좀 더 끌어올리는 것은 또 다른 문제겠지만 말이다.)
빠진 데이터가 많다면 어떻게 처리하면 좋을까? 물론 분석하고자 하는 목표와의 연관성에 따라 달라지겠지만 목표와의 연관성도 떨어지고 데이터 자체로서의 활용 가치도 별로 없다면 우선 그 컬럼을 삭제해 버리는 방법이 있을 것이다.
지난번 IBM의 Customer Data의 경우 빠진 데이터가 없어 캐글에서 오리엔테이션 격이자 상징적인 프로젝트라고 할 수 있는 타이타닉 데이터를 사용해 빠진 연습하고자 한다. 미싱노(MissionNo.)라는 결측치를 시각화해주는 그래프를 사용하면 타이타닉 데이터에 Age(나이)와 Cabin(선실)에 결측값이 많음을 알 수 있다.
타이타닉 프로젝트의 분석 목표는 주어진 데이터를 바탕으로 승객의 생존 여부, 즉 Survived 컬럼의 값을 예측하는 것이다. 우선 PassengerID 컬럼의 경우 데이터의 유니크 값이 891개로 전체 행의 수와 같다. 승객의 고유 번호로 생존과 상관이 없는 컬럼이여서 삭제하려고 한다.
열 삭제는 앞에서도 잠깐 나왔지만 df. drop('컬럼명', axis = 1) 함수를 사용하면 된다. 행 역시 인덱스 라벨로 제거할 수 있는데, 이 때는 축의 방향을 0으로 설정하면 된다.
누락이 있는 모든 행을 삭제하고 싶다면 df.dropna()를 사용하면 된다. 단, 이 경우 나이 컬럼에 빈 값이 177개, 캐빈(객실) 컬럼에 빈 값이 687개나 있어서 남아나는 행이 거의 없을 것이다.
나이와 객실 데이터가 생존여부(목표값)와 상관관계가 없어 마냥 삭제할 수 있는 데이터라 아니라면 빠진 값을 채울 적당한 방법을 생각해 봐야 한다. 분석 목표와 해당 컬럼의 성격에 따라 특정 값을 지정하거나 바로 앞 또는 뒤의 데이터로 채우거나 해당 열의 평균으로 채우는 방법 등이 있을 것이다.
* fillna 함수 - 결측치를 채우는 함수
DataFrame.fillna(value=None, method=None, axis=None, inplace=False, limit=None)
앞 또는 뒤의 값으로 채우기
df.fillna(method='ffill') or df. fillna(method='bfill')
데이터프레임 빈값 채우기
df.fillna(df.mean()) → 전체 빈값을 각 컬럼의 평균으로 채움
df.fillna(df['A'].mean()) → 전체 빈값을 A 컬럼의 평균으로 채움
컬럼의 빈값 채우기
df.A.fillna(df['A'].mean()) → A 컬럼의 빈값을 A 컬럼의 평균으로 채움
나이와 생존여부가 직접적인 관계를 보이지 않지만 177개의 빈 값을 평균 나이로 채우기에는 나이 데이터의 범위가 넓고 다양하다. 승객의 연령대를 추측할 방법이 없을까? 이름에서 힌트를 얻어 보도록 하자.
Name 컬럼에서 호칭만을 추출해 Initial 이라는 새로운 컬럼을 만들고 이니셜 별 나이의 평균으로 빈값을 채워 보도록 하자. 먼저 str.extract( ) 함수를 사용해 period(.) 바로 앞의 호칭만 추출해 새로운 컬럼을 만들자. 뒤에서 다시 설명하겠지만 str.extract( )는 원하는 부분만 출력할 수 있는 판다스 함수이다.
그리고 나이 컬럼을 인수로 받아 컬럼의 평균값으로 해당 열의 빈 값을 채우는 람다함수를 만들고 나이 컬럼에 적용한다. groupby 속성이 있어 (호칭) 그룹별 나이값의 평균 값으로 나이 컬럼의 빈 값들을 채울 수 있을 것이다.
앞서 Name 컬럼에서 원하는 이니셜만 추출했지만 판다스 데이터 분석에 있어 원하는 정보만 추출하기 위해서는 str 함수를 알아두는 게 좋을 것 같다. 판다스의 str( ) 함수는 종류가 너무 많아서 일일이 모두 알 순 없지만 데이터 추출에 있어 유용하게 쓰일 수 있는 몇 가지를 연습하고자 한다.
먼저 인덱싱이다. 우리는 앞서 문자열이나 리스트에서 인덱싱을 통해 원하는 문자나 요소를 추출하는 방법을 배웠는데 판다스 데이터 프레임에서도 마찬가지다. 원하는 컬럼에 있는 문자열(스트링)에서 원하는 문자를 인덱싱을 통해 추출할 수 있다. Cabin(선실) 컬럼에서 첫글자만 추출해보자.
Cabin 컬럼의 데이터를 살펴보면 빈 값을 제외하고 모두 문자와 숫자로 이뤄져 있으며, 형태가 문자+숫자 (예를 들어 B30, C25 등)로 모두 같다. 이럴 경우 문자열의 첫 번째 요소만 출력하면 첫글자가 출력될 것이다.
다음은 str.split() 함수를 사용해서 데이터를 분할하고 인덱싱하는 것이다. 이번에는 Name 컬럼에서 성(Last name)만 출력해보자. Name 컬럼의 데이터를 살펴보면 성이 먼저 나오고 콤마 그리고 호칭과 이름이 나온다. 성만 출력하려면 split 함수로 분할한 다음 첫 번째 요소를 인덱싱하면 될 것 같다.
실제 실행하면 split 함수가 띄어쓰기로 기본값으로 분할을 하기 떄문에 성에 콤마까지 같이 붙어 분할이 된다. 여기서 콤마는 리스트를 나열할 때 콤마가 아니라 원래 데이터에 쓰여진 콤마이다. 이 경우 분할 기준을 콤마와 띄어쓰기, 즉 (', ')로 설정해 분할하고 첫 번째 요소를 인덱싱하니 성공적으로 성만 출력된다.
마지막으로, 처음에는 헷갈리지만 이해해두면 가장 많이 쓰일 str.extract( )함수다. 앞서 이니셜을 추출할 때 사용했는데 str.extract( ) 함수를 사용할 때 염두해 두어야 할 점은 바로 꼭 그룹 ( )을 지정해서 추출하고 싶은 패턴을 입력하는 것이다.
이니셜 추출의 경우 Name 컬럼에서 (.) 앞의 문자열만 출력했다. 괄호 안에 지정된 그룹을 살펴보면 [A-Za-z]은 문자열, +는 그 뒤에 한 개 이상 반복된다는 뜻이다. 그룹 다음에 오는 \는 개별 스트링 앞에 붙이는 기호로, 즉 (.) 앞의 문자열을 출력하라는 의미가 된다.
다음 예를 살펴보자. 앞서 분할과 인덱싱을 통해 출력한 성(Last Name)을 이번에는 str.extract( ) 함수로 패턴을 지정해 출력해 보자. 성은 Name 컬럼에서 가장 먼저 나오는 문자열이므로 아래과 같이 괄호 안에 문자열만 써주면 우선 첫 번째 문자열이 출력될 것이다.
여기서 첫 글자만 출력하고 싶다면 첫번 째 문자열을 의미하는 ([A-Za-z]+) 에서 +를 제외하면 될 것이다.
이 방법을 Cabin에 적용해서 첫 글자만 출력할 수도 있다.
판다스 빠진 데이터 처리하기, Str 함수로 정보 추출 연습하러 가기
https://www.kaggle.com/kyungapark/pandas-missing-data-extract-strings