이번 포스팅에서는 Python Pandas를 활용한 데이터 전처리에 대해서 알아 보겠습니다. 전처리 과정과, 임의의 데이터 세트에 Pandas 라이브러리를 어떻게 적용하는 지 간단한 코드를 통해 확인해 보겠습니다.
데이터 전처리가 필요한 이유
데이터 전처리는 데이터 분석에 있어 가장 중요하고 시간이 많이 걸리는 부분 중 하나 입니다. 데이터를 명확하고 의미 있는 방식으로 이해하고 사용할 수 없다면 데이터는 쓸모가 없습니다.
Lebron James는 미국 농구 팬들이 가장 좋아하는 선수 중 한명입니다. 그를 “LJ”라고 부르는 사람들이 있을 수 있고, 또 누군가는 “Bron”으로 부를 수 있습니다. 두 단어가 동일한 선수를 지칭하고 있다고 하더라도, 제 3자가 해당 단어를 볼 때, 동일인을 말하는 것인지는 확실하지 않기 때문에 데이터를 수정하는 것이 필요합니다.
Lebron James에 대한 모든 이상한 값을 분석하고 단일 기준으로 통일된 이름으로 변경해야 합니다. 이를 통해 제 3자가 데이터를 보더라도 한 명의 농구 선수를 의미하는 것으로 인식할 수 있어야 합니다. 이러한 처리 작업 이후에 역대 농구 선수 중 최고의 선수를 묻는 질문에 그를 최고로 뽑은 사람들의 실제 수를 계산할 수 있습니다.
데이터가 지저분해질 수 있는 방법이 다양하기 때문에 데이터를 정리할 수 있는 방법에도 여러 가지 있습니다. Python의 대표적인 데이터 분석 관련 라이브러리인 Pandas를 사용하여 데이터를 깔끔하게 전처리하는 방법을 보여 드리겠습니다.
중복 값 처리
데이터 세트에서 일반적으로 가장 먼저 수행하는 데이터 전처리 작업 중 하나는 중복 값 처리입니다. 중복 값은 일반적으로 모든 열의 값이 동일하다는 것을 의미합니다. Python에는 중복된 값을 빠르고 삭제하는 함수가 있습니다.
# # DataFrame에서 모든 중복된 값 삭제
dataFrameName.drop_duplicates()
drop_duplicates 함수는 dataframe에서 모든 중복 값을 삭제하고, 매개변수 “subset”을 입력하면 값이 고유해야 하는 특정 열에서 중복 값을 삭제할 수 있습니다.
# UniqueColumn의 모든 중복 값 삭제
dataFrameName.drop_duplicates(subset = ["UniqueColumn"])
drop_duplicates 함수에 대한 자세한 설명은 drop_duplicates 함수 설명 바로가기 를 참고 하시면 됩니다.
분석에 관련 없는 열 삭제하기
데이터 전처리의 일부는 분석에 중요한 열과 그렇지 않은 열을 결정하는 것입니다. 일반적으로 대규모 데이터 세트를 모두 가져올 때 분석을 수행하는 데 필요하지 않은 열도 포함되어 있습니다. 분석에 전혀 필요하지 않고, 원치 않는 열을 모두 제거하고 필요한 데이터만 사용할 수 있는 방법이 있습니다. drop 함수를 사용하면 이를 수행할 수 있습니다.
# unwanted_columns에 나열된 모든 열을 삭제하기
dataFrameName.drop(columns = [unwanted_columns])
# drop 함수 사용 예시
dataFrameName.drop(columns = ['col1','col2','col3'])
# => dataFrameName 데이터프레임에 포함되어 있는 'col1','col2','col3' 열 삭제하기
drop 함수를 사용하면 원하지 않는 모든 열을 columns 매개변수의 리스트로 나열하여 삭제할 수 있습니다. drop_duplicates 함수에 대한 자세한 설명은 drop 함수 설명 바로가기 를 참고 하시면 됩니다.
동일한 데이터 유형 생성하기
데이터세트에서 동일한 정보에 대해 데이터 표현 형식이 다양할 수 있습니다.
예를 들어 start_date라는 날짜를 나타내는 열이 있다고 가정해 보겠습니다. December 20, 2022 형식으로 날짜가 나열될 수 있고, 20–12–2022 형식 및 12/20/22 형식으로 표현될 수 있습니다.
이 날짜는 모두 같은 날을 나타내지만 표현 형식은 완전히 다릅니다. 숫자 값이 데이터 세트에서 문자열로 표시될 수도 있고, 그 반대의 경우도 있을 수 있습니다. Pandas 에서는 이러한 유형의 데이터를 처리하기 위한 간단한 방법들이 존재합니다.
to_datetime() : 열을 날짜/시간 형식으로 변경
# 한 개의 열을 날짜/시간 형식으로 변환
pd.to_datetime(dataFrameName[column_name])
to_datetime() : astype(‘int’) : 열을 int 형식으로 변경
# 한 개의 열을 정수 형식으로 변환
dataFrameName['col_1'].astype('int')
# 여러 개의 열을 정수 형식으로 변환
dataFrameName.astype({"col_1":"int","col_2":"int"})
# 모든 열을 정수 형식으로 변환
dataFrameName.astype('int')
to_string() / as_type(str) : 열을 문자열 형식으로 변경
# 한 개의 열을 문자열 형식으로 변경
dataFrameName[column].to_string()
# 모든 열을 문자열 형식으로 변경
dataFrameName.astype(str)
astype(float) : 열을 부동 형식으로 변경
# 한 개의 열을 부동 형식으로 변경
dataFrameName['Fee'].astype(float)
# 여러 개의 열을 부동 형식으로 변경
dataFrameName.astype({'col_1':'float','col_2':'float'})
# 모든 열을 부동 형식으로 변경
dataFrameName.astype(float)
Pandas에서 열의 데이터 유형을 변경하는 방법에는 여러 가지가 있습니다.
더 많은 것이 있지만 가장 자주 사용하는 함수들이며, 데이터 전처리를 하는 데 매우 효과적입니다.
결측치 처리
데이터 전처리에 있어 또 다른 중요한 부분은 결측치를 처리하는 방법을 아는 것입니다.
모든 데이터세트가 완전 무결하지 않습니다. 실제로 대부분의 데이터세트는 그렇지 않습니다.
행이나 열에 결측치가 있을 때 수행해야 할 작업을 알아야 합니다. 누락된 값을 처리하는 가장 일반적인 방법은 (1) 의미 있는 값으로 채우거나(결측치 대체), (2) 누락된 값이 있는 행을 삭제하는 것입니다. Pandas 라이브러에서는 이를 수행할 수 있는 함수를 제공합니다.
결측치 찾기
수천 또는 수십, 수백만 개의 행이 있는 데이터 세트를 처리하는 경우 결측치가 있는 모든 행을 확인하지 못할 가능성이 있습니다.
데이터세트에서 결측치가 있는 위치를 표시하기 위해 데이터를 필터링할 수 있는 두 가지 주요 방법이 있습니다.
결측치가 있는 열 찾기
# Null 또는 누락된 값이 포함된 열로만 dataFrameName를 필터링
dataFrameName.columns[df.isnull().any()]
결측치가 있는 행 찾기
# null 또는 누락된 값이 포함된 행으로만 dataFrameName를 필터링
dataFrameName[dataFrameName.isnull()]
결측치 대체
모든 결측치를 다른 의미 있는 값으로 채울 수 있습니다. 숫자 값의 경우 0을 선택하거나 해당 열 내 다른 값의 평균 또는 중앙값을 선택할 수 있습니다. 범주형 값의 경우 누락된 값을 “unknown”이라고 부르도록 선택할 수 있습니다. Pandas에서는 fillna를 사용하여 이 모든 작업을 수행할 수 있습니다.
# dataFrameName의 모든 결측치를 "unknown"으로 채우기
dataFrameName.fillna("unknown")
# 'col_1' 열의 누락된 값을 0으로 채우기
dataFrameName['col_1'].fillna(0)
결측치 삭제
결측치가 있는 데이터를 삭제해야 하는 경우도 있습니다. 중요한 특정 열의 데이터가 없으면 데이터로서 의미도 없어지는 데이터는 삭제해야 합니다.
결측치가 없는 완전한 데이터만을 활용하여 분석하여 통찰력 있는 데이터 분석 결과를 얻을 수 있습니다.
Pandas 라이브러리에서 누락된 데이터가 있는 행을 제거하는 간단한 방법은 dropna 함수를 사용하는 것입니다.
# 데이터프레임에 존재하는 모든 결측치를 제거하는 방법
dataFrameName.dropna()
# 특정 열에 존재하는 모든 결측치를 제거하는 방법
dataFrameName['col_1'].dropna()
구조적 오류 처리
데이터 세트에서 구조적인 오류가 있을 수 있는 방법에는 여러 가지가 있습니다. 철자가 틀린 경우, 데이터에 쓸모없는 공백이 있는 경우, 대/소문자가 섞여 있는 경우, 우리가 원하지 않는 방식으로 형식이 지정된 경우 등.
데이터 세트의 열을 동일한 형식으로 균일하게 만드는 4가지 매우 인기 있는 방법을 제공할 것이며, 나머지는 쉽게 얻을 수 있기를 바랍니다.
Title
이름이나 장소를 나타내는 열에서는 문장의 첫 글자를 모두 대문자로 쓰고 나머지 글자는 모두 소문자로 쓰는 것이 일반적입니다. 데이터 세트에 이 작업을 수행하여 특히 이름 및 위치 열에 통일성을 부여할 수 있습니다. Pandas 라이브러리에는 .title()이라는 메서드를 사용하여 이 작업을 쉽게 수행할 수 있습니다.
# 열의 각 단어의 첫 문자열은 대문자로, 나머지는 소문자로 변환
dataFrameName['col_1'].str.title()
.upper(), .lower(), .capitalize() 및 .casefold()를 사용하여 균일성을 만들 수도 있습니다. 데이터 분석의 목적, 이용, 상황에 맞게 메서드를 사용하면 됩니다.
Strip (특정 문자열 제거)
데이터 세트를 보면, 가끔 앞, 끝 또는 중간에 원하지 않는 공백과 문자가 있는 열이 있습니다. Strip을 사용하면 원하지 않는 공백과 문자를 제거할 수 있습니다.
특정 문자를 지정하지 않으면, 불필요한 공백을 제거합니다. 삭제하려는 문자를 지정하면 Pandas 라이브러리는 지정된 문자열 내의 모든 문자를 제거합니다.
# 맨 끝에 있는 공백 제거
dataFrameName['col_1'].str.strip()
# 특정 문자열 왼쪽에 있는 모든 문자 제거
# Ex) 특정 문자열이 1, 2, 3, . 인 경우
dataFrameName['col_2'].str.lstrip('123.')
# 특정 문자열 오른쪽에 있는 모든 문자 제거
# Ex) 특정 문자열이 새로운 줄, 탭, 공백 또는 쉼표인 경우
dataFrameName['col_2'].str.rstrip('\n\t ,')
Replace (특정 문자열 대체)
포스팅 글 앞머리(데이터 전처리가 필요한 이유)에서 Lebron James가 “LJ”, “Bron” 및 “lebron Jams”와 같이 자신의 이름으로 여러 가지 다른 값을 부여한 이전 예를 기억하십니까?
포스팅 글 앞머리(데이터 전처리가 필요한 이유)에서 설명한 이유로 특정 문자열을 대체해야 합니다. Pandas 라이브러리의 replace 함수를 사용하면 하나 이상의 주어진 값을 다른 값으로 바꿀 수 있습니다.
# 구문:
dataFrameName.replace(old_value, new_value)
# Ex) 100 을 500 으로 모두 대체하기
dataFrameName.replace(100, 500)
# 하나의 요소를 하나의 값으로 대체
# Ex) player_name 열에 있는 "LJ"의 모든 값을 "Lebron James"로 대체
dataFrameName['player_name'].replace("LJ", "Lebron James")
# 여러 요소를 하나의 값으로 대체
# Ex) player_name 열에 있는 "LJ", "Bron" 및 "lebron Jams"의 모든 값을 "Lebron James"로 대체
dataFrameName['player_name'].replace(["LJ", "Bron", "lebron Jams"], "Lebron James")
# 여러 요소를 여러 값으로 대체
# Ex) 모든 "LJ" 값을 "Lebron James"로 대체하고, 모든 "SC"의 값을 "Steph Curry"로 대체
dataFrameName['player_name'].replace(["LJ", "SC"], ["Lebron James", "Steph Curry"])
Apply
데이터프레임이나 열에 특정 함수를 수행하고 싶지만, 해당 함수가 Pandas 라이브러리에 없는 경우가 있습니다.
예를 들어, 특정 나이가 아닌 나이의 범위를 생성해야 한다고 가정해 보겠습니다
(개별 관측치의 나이가 40보다 크거나 같으면 ’40 이상’, 40보다 작으면 ’40 미만’).
모든 단일 행을 반복하여 할당해야 하는 나이 범위를 확인해야 하는 경우 이 작업을 수행하기 어려울 수 있습니다
(iterrows 메소드를 사용할 수 있는데, 이는 다음 포스팅에서 설명하겠습니다).
이런 유형의 문제는 .apply() 메소드를 사용할 수 있습니다. 이 메소드는 생성한 함수를 데이터프레임 열에 전달할 수 있으며 결과는 모든 단일 행에 적용됩니다.
# 구문:
dataFrameName[column_name].apply(function_name)
# Ex) 'age' 열의 모든 값에 대한 '40 이상', '40 미만' 값 생성
def create_age_range(age):
if age > 40:
return "over 40"
else:
return "under 40"
dataFrameName['age'].apply(create_age_range)
Pandas 라이브러리에 문제 해결을 위한 특정 메소드나 함수가 없더라도 직접 만들어서 데이터프레임에 적용할 수 있습니다.
결론
지금까지 데이터 전처리를 쉽게 할 수 있는 Pandas 라이브러리에서 제공하는 몇 가지 방법에 대해서 살펴보았습니다. 데이터 전처리 이후에는 이후 데이터의 추세를 확인하고, 필터링하고, 쿼리하여 데이터를 탐색하는 방법에 대해서 알아 보겠습니다.
감사합니다!