귀퉁이 서재

DATA - 25. Data Wrangling (Cleaning Data) 본문

데이터 분석

DATA - 25. Data Wrangling (Cleaning Data)

Baek Kyun Shin 2019. 5. 20. 23:33

Data Wrangling의 3단계 (Gather Data -> Assess Data -> Clean Data) 중 마지막 단계인 Cleaning Data입니다. Assess Data에서 이슈별로 (Quality, Tidiness) 어떤 데이터를 어떻게 정제해야하는지 정의를 했을 겁니다. 이제 실제로 정제를 하는 단계입니다. 데이터 정제를 할 때는 Missing Value를 먼저 채워주고, Tidiness 문제를 해결한 뒤, 마지막으로 Quality 문제를 해결하면 됩니다. 또한 원본 DataFrame을 유지하기 위해 꼭 copy()해서 Cleaning을 하도록 합니다. (Reference1) 

데이터 정제(Cleaning) 실습

데이터를 정제하는 실습을 해보겠습니다. 3가지 데이터셋 환자 정보(patients.csv), 치료 효과에 대한 기록(treatments.csv), 부작용에 대한 기록(adverse_reactions.csv)이 있습니다. 이는 정제되지 않은 데이터입니다. 이를 분석하기 용이하게 정제(Cleaning)하는 것이 이번 챕터의 목적입니다. 

전체 코드와 이미지를 본 블로그에 담으려 했는데 길이가 너무 길어 제 깃헙 링크를 남기겠습니다. 깃헙이 렌더링이 안되거나 오래걸리면 nbviewer로 보시기 바랍니다. 이 챕터를 보시는 것보다 깃헙 링크의 notebook (ipynb)를 보시는 것이 더 좋겠습니다. DataFrame을 출력하는 것까지 하면 상당히 길어 도저히 본 블로그에 담을 수가 없었습니다. 깃헙 링크를 참고하면서 블로그를 봐주시기 바랍니다.

1) In[3]부터 In[8]까지가 DataFrame, 데이터의 갯수와 타입을 관찰하는 부분입니다. 

2) In[6]에서 zip code가 zip_code 491 non-null float64라고 되어있습니다.  zip code가 float 타입으로 되어있는데, 사칙연산이 가능하지 않기 때문에 string 타입이어야 합니다. (Zip code is a float not a string)

3) Out[3]의 20번째 행의 zip코드는 4자입니다. 02382가 2382로 잘못 표기가 된 것입니다. (엑셀에 02382를 기입하면 앞의 0은 자동으로 삭제가 되기 때문이죠.) (Zip code has four digits sometimes)

4) Out[3]의 4번째 행 Tim Neudorf의 height가 27입니다. 다른 사람들을 봤을 때 height 단위는 inch임을 알 수 있습니다. 하지만 27inch는 69cm 가량입니다. 몸무게가 192파운드이고, bmi가 26인 것을 봤을 때 키는 27inch가 아니라 72inch입니다. 오타가 난 것입니다. (Tim Neudorf height is 27 inch instead of 72 inch)

5) Out[3]의 2행과 3행의 State 열을 비교해보겠습니다. 하나는 full name(Nebraska)으로 되어있고 하나는 약자로 (NJ)되어 있습니다. 이도 일관되게 통일해주어야 합니다.(Full state names sometimes, abbreviations other times)

6) 찾는게 힘들겠지만 David Gustafsson이 Dsvid Gustafsson로 오타가 났습니다. (Dsvid Gustafsson)

7) In[6]를 보면, assigned sex, state, birthdate column은 모두 object 타입입다. assigned sex와 state는 category 타입, birthdate는 datetime 타입으로 바꾸어주는 것이 좋습니다.(Erroneous datatypes (assigned sex, state, zip_code, and birthdate columns)

8) Out[3]의 Contact column을 보면 전화번호와 이메일이 겹쳐 있습니다. 이를 분리해줄 필요가 있습니다. (Contact column in patients table should be split into phone number and email)

9) 또한 전화번호 형식도 제각각이라 통일해주어야 합니다. (Multiple phone number formats)

10) Jakobsen, Gersten, Taylor에 대한 중복 행이 있습니다. (Multiple records for Jakobsen, Gersten, Taylor)

11) Zaitseva는 lbs대신 kgs으로 표기가 되었습니다. (kgs instead of lbs for Zaitseva weight)

12) Out[4]의 hba1c_change column 중 NaN 값이 있습니다. hba1c_change는 hba1c_start - hba1c_end입니다. hba1c_start는 약 복용전 hba1c 레벨, hba1c_end는 약 복용 후 hba1c 레벨입니다. auralin과 novodra는 서로 다른 약제입니다. auralin과 novodra를 먹인 환자중 hba1c 수치가 얼마나 많이 낮아졌는지를 측정한 테이블이 treatments입니다. hba1c 수치가 낮을 수록 약의 효과가 좋은 것입니다. hba1c_change column을 새로 계산해 채워넣어주어야 합니다. (Missing HbA1c changes)
(Inaccurate HbA1c changes)

13) Out[4]의 auralin과 novodra의 값이 41u-48u, 40u-45u와 같이 되어 있습니다. u는 unit의 약자입니다. 41u-48u의 의미는 시작할 때 41unit만큼의 약제를 먹었고, 끝날때쯤은 48u만큼의 약을 먹었다는 뜻입니다. 이 수치는 사칙연산이 가능하므로 u를 없애 string(object) 타입이 아닌 int 타입으로 바꿔줘야 합니다. (The letter 'u' in starting and ending doses for Auralin and Novodra)
(Erroneous datatypes (auralin and novodra columns))

14) 또한, Out[4]의 auralin과 novodra column에는 treatment 종류, start unit, end unit 이렇게 3개의 variable이 있습니다. 2개의 column을 3개로 구분해줘야 합니다. 그리고 Null 값이 -로 표현되어 있습니다.(Three variables in two columns in treatments table (treatment, start dose and end dose))
(Nulls represented as dashes (-) in auralin and novodra columns)

15) Patients와 Treatments의 give_name, surname을 보면 어떤 건 대문자로 시작하고 어떤 건 소문자로 시작합니다. 이를 소문자로 시작하게 바꾸어 주어야 합니다. (Lowercase given names and surnames)

16) Out[4]에서 Treatments의 행 갯수는 280개입니다. 하지만 실제 갯수는 350개입니다. treatments_cut.csv 참고 (Missing records (280 instead of 350))

17) Out[5]를 보면 given_name, surname, adverse_reaction으로 총 3개의 column이 있습니다. 이는 treatments table과 합치는 게 좋겠습니다. (Adverse reaction should be part of the treatments table)

18) Patients, Treatments, Adverse_reaction 테이블에 모두 given_name, surname이 있습니다. patient ID를 고유의 값으로 하고 중복된 column은 제거하는 것이 좋겠습니다. (Given name and surname columns in patients table duplicated in treatments and adverse_reactions table)

위에 주절주절 설명한 것이 Out[22]에 정리되어 있습니다.

Quality

patients table
Zip code is a float not a string
Zip code has four digits sometimes
Tim Neudorf height is 27 in instead of 72 in
Full state names sometimes, abbreviations other times
Dsvid Gustafsson
Missing demographic information (address - contact columns) (can't clean yet)
Erroneous datatypes (assigned sex, state, zip_code, and birthdate columns)
Multiple phone number formats
Default John Doe data
Multiple records for Jakobsen, Gersten, Taylor
kgs instead of lbs for Zaitseva weight

treatments table
Missing HbA1c changes
The letter 'u' in starting and ending doses for Auralin and Novodra
Lowercase given names and surnames
Missing records (280 instead of 350)
Erroneous datatypes (auralin and novodra columns)
Inaccurate HbA1c changes (leading 4s mistaken as 9s)
Nulls represented as dashes (-) in auralin and novodra columns

adverse_reactions table
Lowercase given names and surnames

Tidiness
Contact column in patients table should be split into phone number and email
Three variables in two columns in treatments table (treatment, start dose and end dose)
Adverse reaction should be part of the treatments table
Given name and surname columns in patients table duplicated in treatments and adverse_reactions tables

 

모든 코드는 document를 보며 차근차근 따라가면 됩니다. In[29] 부분만 추가 설명을 드리겠습니다.

patients_clean['phone_number'] = patients_clean.contact.str.extract('((?:\+\d{1,2}\s)?\(?\d{3}\)?[\s.-]?\d{3}[\s.-]?\d{4})', expand=True)
patients_clean['email'] = patients_clean.contact.str.extract('([a-zA-Z][a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.][a-zA-Z]+)', expand=True)
# Note: axis=1 denotes that we are referring to a column, not a row
patients_clean = patients_clean.drop('contact', axis=1)

위 코드는 Contact column에서 정규표현식을 사용해 전화번호와 이메일을 추출합니다. 아래 정규표현식 관련된 링크를 참고해주시기 바랍니다. 아주 유용합니다.

정규표현식 Tutorial (Reference2)전화번호 정규표현식 (Reference3), E-mail 정규표현식 (Reference4)

참고로, 정규표현식에서 괄호() 안에 있는 것을 group이라고 합니다. 정규표현식은 group을 capture해서 사용자에게 보여주는데 ?:는 해당 group은 capture하지 않는다는 뜻입니다. 따라서 (?: 어쩌구저쩌구)로 되어 있는 정규표현식은 matching은 되지만 capture는 되지 않습니다. 본 링크 (Reference5)에서 ?:가 있는 group과 없는 group의 차이를 오른쪽 결과에서 볼 수 있습니다.

In[33]에서 merge를 사용하는데, Join과 merge관련해서는 본 링크 (Reference6)를 참고하시기 바랍니다.

References

Reference1: Why should I make a copy of data frame in pandas

Reference2: RegexOne Tutorial

Reference3: Regular expression to match standard 10 digit phone number

Reference4: Almost Perfect Email Regex

Reference5: Regular expression 101

Reference6: Join And Merge Pandas Dataframe

 

Comments