본문 바로가기
개발일지/Pandas

매우중요 pandas 판다스 기초 16 문자열 가공 Cleaning Data

by 개발에정착하고싶다 2022. 7. 28.
320x100

정말 중요하다 이번 파트는

# Cleaning Data

## First Inspection / Handing inconsistent Data

### Titanic Dataset

import pandas as pd
titanic = pd.read_csv('titanic_imp.csv')
titanic.head()

'''

    Survived	Class	Gender	Age	Sipsp	Parch	Fare	Emb	Deck
0	0	3	male	22.0	1	0	$7.25	S	NaN
1	1	1	female	38.0	1	0	$71.2833	C	C
2	1	3	female	26.0	0	0	$7.925	S	NaN
3	1	1	female	35.0	1	0	$53.1	S	C
4	0	3	male	35.0	0	0	$8.05	S	NaN
'''
titanic.info()

'''
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 894 entries, 0 to 893
Data columns (total 9 columns):
 #   Column    Non-Null Count  Dtype 
---  ------    --------------  ----- 
 0   Survived  894 non-null    object
 1   Class     894 non-null    int64 
 2   Gender    894 non-null    object
 3   Age       758 non-null    object
 4   Sipsp     894 non-null    int64 
 5   Parch     894 non-null    int64 
 6   Fare      894 non-null    object
 7   Emb       892 non-null    object
 8   Deck      203 non-null    object
dtypes: int64(3), object(6)
memory usage: 63.0+ KB
'''

# Survived는 object -> int
# Age도 object -> float
# Fare도 $를 빼버리고 object에서 float으로 전환해야한다.
titanic.describe()

'''
	Class	Sipsp	Parch
count	894.000000	894.000000	894.000000
mean	2.309843	0.522371	0.381432
std	0.835370	1.101283	0.805171
min	1.000000	0.000000	0.000000
25%	2.000000	0.000000	0.000000
50%	3.000000	0.000000	0.000000
75%	3.000000	1.000000	0.000000
max	3.000000	8.000000	6.000000
'''
titanic[['Survived', 'Gender', 'Age','Fare', 'Emb', 'Deck']].describe()

'''

    Survived	Gender	Age	Fare	Emb	Deck
count	894	894	758	894	892	203
unique	4	2	92	248	3	7
top	0	male	Missing Data	$8.05	S	C
freq	551	580	41	43	647	59
'''

# Survived의 unique는 죽냐, 사냐 둘중에 하나여야하기 때문에 4라는 값은 이상치다.
# 그 외에도 Age의 Missing Data등을 보았을때, 아무튼 문제가 있는 것으로 추정 가능하다.
titanic.Survived.unique()

'''
array(['0', '1', 'yes', 'no'], dtype=object)
'''
titanic.Survived.value_counts()

'''
0      551
1      341
yes      1
no       1
Name: Survived, dtype: int64
'''
titanic.Survived.replace('yes', '1', inplace=True)
titanic.Survived.replace('no', '0', inplace = True)
titanic.Survived.unique()
# array(['0', '1'], dtype=object)
# 나는 위와같이 전개하여 좀 더 재래식으로 풀었지만
# 강사님의 코드는 다음과 같았다.
titanic.Survived.replace(to_replace = ['yes', 'no'], value = [1, 0], inplace = True)
titanic.Survived.value_counts()
'''
0    552
1    342
Name: Survived, dtype: int64
'''

# 흠.. 흥미롭군.. 처음에 1,0,yes,no 이렇게 4가지가 있을때 데이터 타입이 object였다.
# 그래서 나는 생각하기로 전체가 string type으로 잡혀있기 때문에
# 먼저 yes와 no를 기존과 마찬가지인 string 타입의 숫자로 만들어주고 (왜냐하면 object일 경우 또다시 string 0과 1, int의 0과 1 이렇게 나뉠줄 알았다.)
# 추후에 한 번에 데이터 타입을 변환해주려고 했다.
# 하지만 지금 생각해보면 설사 string type 0과 1, 그리고 int type 0과 1이라 해도
# 처음 yes와 no를 int로 전환해주는게 맞다고 판단이 들었다.
# 왜냐하면 어차피 string type들이라면 int타입으로 전환시 자동적으로 동일 타입의 수로 계산이 될 것이기 때문이다.

# 더불어서 value값에 아예 int를 넣어주니깐, yes와 no를 제외하곤 어차피 int였다는 듯이 자동으로 데이터 타입이 전체적으로 int로 바뀌었다.


## Olympic Dataset

summer = pd.read_csv('summer_imp.csv')
summer.head()

'''

    Year	City	Sport	Discipline	Athlete Name	Country	Gender	Event	Medal
0	1896	Athens	Aquatics	Swimming	HAJOS, Alfred	HUN	Men	100M Freestyle	Gold Medal
1	1896	Athens	Aquatics	Swimming	HERSCHMANN, Otto	AUT	Men	100M Freestyle	Silver
2	1896	Athens	Aquatics	Swimming	DRIVAS, Dimitrios	GRE	Men	100M Freestyle For Sailors	Bronze
3	1896	Athens	Aquatics	Swimming	Malokinis, Ioannis	GRE	Men	100M Freestyle For Sailors	Gold Medal
4	1896	Athens	Aquatics	Swimming	Chasapis, Spiridon	GRE	Men	100M Freestyle For Sailors	Silver
'''

# tail은 애초에 summer로 앞뒤를 확인했으니 패스
# 열 이름에 공백이 들어있는건 좋지 않다고 한다.
# 하기사 변수.컬럼명으로 import할때도 공백이 있으면 [컬럼]방식만 작동된다.

summer['Athlete Name']

'''
0                     HAJOS, Alfred 
1                  HERSCHMANN, Otto 
2                 DRIVAS, Dimitrios 
3                Malokinis, Ioannis 
4                Chasapis, Spiridon 
                    ...             
31165            JANIKOWSKI, Damian 
31166     REZAEI, Ghasem Gholamreza 
31167                TOTROV, Rustam 
31168             ALEKSANYAN, Artur 
31169                LIDBERG, Jimmy 
Name: Athlete Name, Length: 31170, dtype: object
'''
# 그래서 컬럼 이름을 변경해준다.

summer.rename(columns= {'Athlete Name': 'Athlete_Name'}, inplace = True)
# 입력하는 것도 그 사이에 다 까먹었었고, 원리만 몸에 남았었다;
summer.head(2)

'''

    Year	City	Sport	Discipline	Athlete_Name	Country	Gender	Event	Medal
0	1896	Athens	Aquatics	Swimming	HAJOS, Alfred	HUN	Men	100M Freestyle	Gold Medal
1	1896	Athens	Aquatics	Swimming	HERSCHMANN, Otto	AUT	Men	100M Freestyle	Silver
'''
summer.Medal.value_counts()

'''
Gold          10483
Bronze        10372
Silver        10311
Gold Medal        4
Name: Medal, dtype: int64
'''
summer.Medal.replace('Gold Medal', 'Gold', inplace=True)

'''
강사님의 코드는
summer.Medal.replace(to_replace = 'Gold Medal', value = 'Gold', inplace = True)
였으나,
내가 써준 코드는 to_replace와 value가 생략이 가능한 것으로 알고있으니, 결과적으론 동일한 결과값을 가질 수 있다.
'''
summer.Medal.value_counts()
'''
Gold      10487
Bronze    10372
Silver    10311
Name: Medal, dtype: int64
'''
# iloc의 순서는 행(rows), 열(columns) 꼭 기억하자
summer.iloc[:,1:].describe()

'''
    City	Sport	Discipline	Athlete_Name	Country	Gender	Event	Medal
count	31170	31170	31170	31170	31166	31170	31170	31170
unique	22	43	67	22763	147	2	666	3
top	London	Aquatics	Athletics	PHELPS, Michael	USA	Men	Football	Gold
freq	3567	4170	3639	22	4586	22751	1497	10487
'''


# String Operations

## Titanic Dataset

titanic.head()

'''
    Survived	Class	Gender	Age	Sipsp	Parch	Fare	Emb	Deck
0	0	3	male	22.0	1	0	$7.25	S	NaN
1	1	1	female	38.0	1	0	$71.2833	C	C
2	1	3	female	26.0	0	0	$7.925	S	NaN
3	1	1	female	35.0	1	0	$53.1	S	C
4	0	3	male	35.0	0	0	$8.05	S	NaN
'''
titanic.info()

'''
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 894 entries, 0 to 893
Data columns (total 9 columns):
 #   Column    Non-Null Count  Dtype 
---  ------    --------------  ----- 
 0   Survived  894 non-null    object
 1   Class     894 non-null    int64 
 2   Gender    894 non-null    object
 3   Age       758 non-null    object
 4   Sipsp     894 non-null    int64 
 5   Parch     894 non-null    int64 
 6   Fare      894 non-null    object
 7   Emb       892 non-null    object
 8   Deck      203 non-null    object
dtypes: int64(3), object(6)
memory usage: 63.0+ KB
'''
# 데이터 타입을 int로 전환 (int라기 보다는 float를 포함한, 전체적인 숫자로 전환해주는 것을 의미하는 것 같다.)
pd.to_numeric(titanic.Fare)
# ValueError: Unable to parse string "$7.25" at position 0
# 이 표현에 유의하자.
# 가끔가다 어떤 포인트에서는 단순히 변수명.컬럼명.원하는함수()
# 이렇게 사용 하는 것이 아니라
# 변수명.컬럼명.str.원하는함수()로 나오기도 한다.
titanic.Fare = titanic.Fare.str.replace('$', '')

# 게다가 replace는 inplace = True의 기능이 없으므로 변수명.컬럼명 = 으로해서 저장해준다.
titanic.Fare.head()

'''
0       7.25
1    71.2833
2      7.925
3       53.1
4       8.05
Name: Fare, dtype: object
'''


## Olympic Dataset

summer.head()

'''

    Year	City	Sport	Discipline	Athlete_Name	Country	Gender	Event	Medal
0	1896	Athens	Aquatics	Swimming	HAJOS, Alfred	HUN	Men	100M Freestyle	Gold
1	1896	Athens	Aquatics	Swimming	HERSCHMANN, Otto	AUT	Men	100M Freestyle	Silver
2	1896	Athens	Aquatics	Swimming	DRIVAS, Dimitrios	GRE	Men	100M Freestyle For Sailors	Bronze
3	1896	Athens	Aquatics	Swimming	Malokinis, Ioannis	GRE	Men	100M Freestyle For Sailors	Gold
4	1896	Athens	Aquatics	Swimming	Chasapis, Spiridon	GRE	Men	100M Freestyle For Sailors	Silver
'''

# 다른건 다 문장의 첫번째 영어가 대문자인 반면에
# Athlete_Name 영역의 필드값에서는 그렇기도하고, 그렇지 않은 값들이 관측된다.
# 이럴경우, 해당 값들을 통일시켜줘야한다.
# 문장의 첫번째 글자만 대문자로 전환해주기
summer.Athlete_Name.str.title()

'''
0                     Hajos, Alfred 
1                  Herschmann, Otto 
2                 Drivas, Dimitrios 
3                Malokinis, Ioannis 
4                Chasapis, Spiridon 
                    ...             
31165            Janikowski, Damian 
31166     Rezaei, Ghasem Gholamreza 
31167                Totrov, Rustam 
31168             Aleksanyan, Artur 
31169                Lidberg, Jimmy 
Name: Athlete_Name, Length: 31170, dtype: object
'''
# 바로 위에서 확인한 값대로 inplace = True가 아닌 방식으로 해당 컬럼에 재 변수 지정해주는 과정을
# '오버라이드'라고 한다.

summer.Athlete_Name = summer.Athlete_Name.str.title()
summer.head()

'''

    Year	City	Sport	Discipline	Athlete_Name	Country	Gender	Event	Medal
0	1896	Athens	Aquatics	Swimming	Hajos, Alfred	HUN	Men	100M Freestyle	Gold
1	1896	Athens	Aquatics	Swimming	Herschmann, Otto	AUT	Men	100M Freestyle	Silver
2	1896	Athens	Aquatics	Swimming	Drivas, Dimitrios	GRE	Men	100M Freestyle For Sailors	Bronze
3	1896	Athens	Aquatics	Swimming	Malokinis, Ioannis	GRE	Men	100M Freestyle For Sailors	Gold
4	1896	Athens	Aquatics	Swimming	Chasapis, Spiridon	GRE	Men	100M Freestyle For Sailors	Silver
'''
summer.loc[summer.Athlete_Name == 'Hajos, Alfred']

# Year	City	Sport	Discipline	Athlete_Name	Country	Gender	Event	Medal
# 아무런 값도 조회되지 않는다. 이런경우에는 다음과 같이 조회해 보자.
summer.iloc[0,4]
# ' Hajos, Alfred '
# 0번 행의 4번 컬럼에 해당하는 값을 호출해왔다.
# 앞, 뒤로 각각 공백이 있다. 그래서 조회가 안되던 것이였다.
# ******** 중요 *********
# 위의 방법을 해결하기 위해서는 몇가지 방법이 있다.

# 1-1 내가 원하는 값이 '포함되어 있다면'그것을 로드하기 - contains
summer.loc[summer.Athlete_Name.str.contains('Hajos, Alfred')]

'''
	Year	City	Sport	Discipline	Athlete_Name	Country	Gender	Event	Medal
0	1896	Athens	Aquatics	Swimming	Hajos, Alfred	HUN	Men	100M Freestyle	Gold
6	1896	Athens	Aquatics	Swimming	Hajos, Alfred	HUN	Men	1200M Freestyle	Gold
'''

# 이 포함된 값을 조회하기 기능인 contains는 매우 유용할 듯 하니 반드시 기억해두자
# 1-2 내가 원하는 값이 '포함되어 있다면'그것을 로드하기 - contains
# 위에서 조회한 방법에서는 변수가 있을 수 있다. 같은 이름이라도
# Hajos, Alfred 아니면 Hajos,Arfred 이렇게, 어떤건 공백이 사이에 있고, 어떤건 공백이 사이에 없을 수도 있다.
# 따라서 한 번더 조회해주자. (아니면 처음부터 이렇게 조회를 해주자. 특별히 겹치는 이름이 아닌이상)

summer.loc[summer.Athlete_Name.str.contains('Hajos')]

'''
Year	City	Sport	Discipline	Athlete_Name	Country	Gender	Event	Medal
0	1896	Athens	Aquatics	Swimming	Hajos, Alfred	HUN	Men	100M Freestyle	Gold
6	1896	Athens	Aquatics	Swimming	Hajos, Alfred	HUN	Men	1200M Freestyle	Gold
'''

# 다시 되새기자면 loc은 기본적으로 문자, 불리언에 의해서 움직이는 조회방식이다.
# 단순히 summer.Athlete_Name.str.contains('Hajos')
# 라고 하게되면 summer.Athlete_Name.str.contains('Hajos') 값이 포함되어있는 행은 True, 포함이 안되어있다면 False를 리턴한다.
# 그리고 이렇게 불리언 값을 내포하고 있는 수식을 summer.loc[]안에 넣으면 비로소 잘 작동된다.
# 양쪽의 공백을 없애주는 코드 - strip()
# 왼쪽의 공백을 없애주는 코드 - lstrip()
# 오른쪽의 공백을 없애주는 코드 - rstrip()

summer.Athlete_Name.str.strip()
'''
0                    Hajos, Alfred
1                 Herschmann, Otto
2                Drivas, Dimitrios
3               Malokinis, Ioannis
4               Chasapis, Spiridon
                   ...            
31165           Janikowski, Damian
31166    Rezaei, Ghasem Gholamreza
31167               Totrov, Rustam
31168            Aleksanyan, Artur
31169               Lidberg, Jimmy
Name: Athlete_Name, Length: 31170, dtype: object
'''
summer.Athlete_Name.head()

'''
0          Hajos, Alfred 
1       Herschmann, Otto 
2      Drivas, Dimitrios 
3     Malokinis, Ioannis 
4     Chasapis, Spiridon 
Name: Athlete_Name, dtype: object
'''

# 조회를 해보면 변화하지 않았다. strip()에는 inplace = True기능이 없으니
# 마찬가지로 오버라이팅을 해주자.
summer.Athlete_Name = summer.Athlete_Name.str.strip()
summer.Athlete_Name.head()

'''
0         Hajos, Alfred
1      Herschmann, Otto
2     Drivas, Dimitrios
3    Malokinis, Ioannis
4    Chasapis, Spiridon
Name: Athlete_Name, dtype: object
'''

# 잘 오버라이팅 되어서 앞,뒤의 공백이 없어졌다.
summer.loc[summer.Athlete_Name == 'Hajos, Alfred']

'''

Year	City	Sport	Discipline	Athlete_Name	Country	Gender	Event	Medal
0	1896	Athens	Aquatics	Swimming	Hajos, Alfred	HUN	Men	100M Freestyle	Gold
6	1896	Athens	Aquatics	Swimming	Hajos, Alfred	HUN	Men	1200M Freestyle	Gold
'''

# 이제는 정상출력 된다.
summer.loc[summer.Athlete_Name == 'Lidberg, Jimmy']

'''
        Year	City	Sport	Discipline	Athlete_Name	Country	Gender	Event	Medal
31169	2012	London	Wrestling	Wrestling Freestyle	Lidberg, Jimmy	SWE	Men	Wg 96 KG	Bronze
'''

# 다른 이름의 선수도 정상적 출력이 된다.
300x250