5장 데이터 사전 처리
누락 데이터 처리
- 머신러닝 등 데이터분석의 정확도는 분석 데이터의 품질에 의해 좌우됨
- 데이터 품질을 높이기 위해서는 누락 데이터, 중복 데이터 등 오류를 수정하고 분석 목적에 맞게 변형하는 과정이 필요함
- 빅데이터에서 원소 데이터 값이 누락되는 경우 -> 데이터를 파일로 입력할 때 빠트리거나 형식을 변환하면서 데이터가 소실되는 경우
- 판다스에서 유효하지 않거나 데이터 값이 존재하는 않은 데이터를 NaN으로 표시
- 머신러닝 분석 모형에 데이터를 입력하기 전에 반드시 누락 데이터를 제거하거나 다른 적절한 값으로 대체하는 과정이 필요
누락 데이터 제거
# NaN 값이 500개 이상인 컬럼을 모두 삭제 -> deck 컬럼
df_thresh = df.dropna(axis=1, thresh=500)
df_thresh.isnull().sum() # 누락 데이터가 삭제되었는지 확인
중복 데이터 처리
- 데이터프레임에서 각 행은 분석 대상이 갖고 있는 모든 속성에 대한 관측값을 뜻함
- 하나의 데이터셋에 동일한 관측값이 2개 이상 중복되는 경우 중복 데이터를 삭제해야 됨
- 동일한 대상이 중복으로 존재하면 분석 결과를 왜곡할 가능성이 있기 때문
중복 데이터 확인
# 데이터프레임 전체 행 데이터 중에서 중복값 찾기
df_dup = df1.duplicated()
중복 데이터 제거
# c2, c3 컬럼을 기준으로 중복 행 제거
df3 = df1.drop_duplicates(subset=['c2', 'c3'])
데이터 표준화
- 실무에서 전하는 데이터셋은 다양한 사람들의 손을 거쳐 만들어짐
- 여러 곳에서 수집한 자료들은 단위 선택, 대소문자 구분, 약칭 활용 등 여러가지 원인에 의해 다양한 형태로 표현
- 동일한 대상을 표현하는 방법에 차이가 있을 경우 분석의 정확도가 현저히 낮아짐
- 데이터 포맷을 일관성 있게 표준화하는 작업 필요
단위 환산
- 한 데이터셋 안에서 서로 다른 측정 단위를 사용한다면, 전체 데이터의 일관성 측면에서 문제가 발생
- 측정 단위를 동일하게 통일해야 함
범주형(카테고리) 데이터 처리
구간 분할
- 데이터분석 알고리즘에 따라서는 연속 데이터를 그대로 사용하기보다는 일정한 구간(bin)으로 나눠서 분석하는 것이 효율적일 때가 있음
- 구간 분할은 경계값을 기준으로 나누고 범주형 인산 변수로 변환하는 과정을 의미
- 3개의 범주로 나누기 위해서는 경계가 4개 필요함
- 0 ~ 100의 출력값
- 저출력 : 0 =< x =< 25
- 중출력 : 25 =< x =< 75
- 고출력 : 75 =< x =< 100
- -> 구간 : 0, 25, 75, 100
더미 변수
- 머신러닝에서는 원핫인코딩
- 범주형 데이터가 2개 이상일 경우 머신런이 알고리즘에서는 범주형 데이터이기보다 연속형 데이터로 연산되기 때문에 0과 1인 2개의 값으로 변경해야됨
# hp_bin 컬럼 horsepoer_dummies = pd.get_dummies(df_auto['hp_bin']).astype('int')
원핫인코딩
토큰에 위치를 부여해서 입력값이 토큰값과 같으면 해당하는 위치에 지정해둔 값을 출력
sklearn
from sklearn import preprocessing
전처리를 위한 encoder 객체 생성
label_encoder = preprocessing.LabelEncoder()
onehot_encoder = preprocessing.OneHotEncoder()
label encoder로 문자열 범주를 숫자형 범주로 변환
onehot_labeled = label_encoder.fit_transform(df_auto['hp_bin'].head(30))
onehot_labeled
- 고출력=0, 보통출력=1, 저출력=2
- 위의 1차원 배열을 아래의 2차원 배열로 변환시킴
- 머신러닝에 데이터를 넣을 때는 array 형태가 기본
onehot_reshaped = onehot_labeled.reshape(len(onehot_labeled), 1)
onehot_reshaped.shape
onhot_fitted = onehot_encoder.fit_transform(onehot_reshaped)
onhot_fitted.toarray()
## 정규화
- 각 변수에 들어있는 숫자 데이터의 상대적 크기 차이 때문에 머신러닝 분석 결과가 달라질 수 있음
- 각 열에 속하는 데이터값을 동일한 크기 기준으로 나눈 비율로 나타내는 것 = 정규화
- min-max
- standard scailing
df_auto['horsepower'].describe()
출력 컬럼의 최대값의 절대값으로 모든 데이터를 나눠서 저장
min_x = df_auto['horsepower'] - df_auto['horsepower'].min()
min_max = df_auto['horsepower'].max() - df_auto['horsepower'].min()
df_auto['horsepower'] = min_x / min_max
df_auto['horsepower'].describe()
-> 0에서 1 사이의 값을 갖게 됨
-> 값에 대한 크다/작다의 정보는 같지만 스케일만 달라짐
-> min-max 스케일링
## 시계열 데이터(time series)
- 주식, 환율 등 금융데이터를 다루기 위해 개발된 판다스는 시계열 데이터를 다루는 여러 기능을 제공
- 시계열 데이터를 데이터프레임의 행 인덱스로 사용하면 시간으로 기록된 데이터를 분석하는 것이 편리
- 판다스의 시간 표시 방식은 Timestamp와 Period가 있음
### 문자열을 Timestamp로 변환
- 판다스 to_datetime() 함수를 사용하면 문자열 등 다른 자료형을 판다스 Timestamp를 나타내는 datetime64 자료형으로 변환 가능
문자열 데이터(시리즈 객체)를 판다스 Timestamp로 변환
df_stock['new_Date'] = pd.to_datetime(df_stock['Date'])
시계열 값으로 변환된 컬럼을 인덱스로 설정. 기존 날짜 컬럼은 삭제
df_stock.set_index('new_Date', inplace=True)
del df_stock['Date']
### Timestamp를 Period로 변환
- to_period() 함수를 이용하면 일정한 기간을 나타내는 Period 객체로 변환할 수 있음
- frep 옵션(frequency. 반복)에 기준이 되는 날짜를 지정
날짜 형식의 문자열로 구성된 리스트
dates = ['2019-01-01', '2020-03-01', '2021-06-01']
문자열 데이터(시리즈 객체)를 판다스 Timestamp로 변환
ts_dates = pd.to_datetime(dates)
날짜 기준
ts_dates.to_period(freq='D')
월 기준
ts_dates.to_period(freq='M')
연 기준
ts_dates.to_period(freq='Y')
### 시계열 데이터 만들기
#### Timestamp 배열
- 판다스 date_range() 함수를 사용하면 여러 개의 날짜(Timestamp)가 들어있는 배열 형태의 시계열 데이터를 만들 수 있음
- range() 함수로 숫자 배열을 만드는 것과 유사
Timestamp 배열 만들기
ts_ms = pd.date_range(start='2019-01-01',
end=None,
periods=6,
freq='MS', # 시간 간격
tz = 'Asia/Seoul') # 시간대(timezone)
ts_me = pd.date_range(start='2019-01-01',
end=None,
periods=6,
freq='3M', # 시간 간격(3M : 3개월 단위)
tz = 'Asia/Seoul')
#### Period 배열
- 판다스 period_range() 함수는 여러 개의 기간이 들어있는 시계열 데이터를 생성
1시간 간격 Period 배열
pr_m = pd.period_range(start='2019-01-01', # 날짜 범위의 시작
end=None, # 날짜 범위의 끝
periods=3, # 생성할 Period 개수
freq='H') # 기간의 길이(H: 시간)
2시간 간격 Period 배열
pr_m = pd.period_range(start='2019-01-01', # 날짜 범위의 시작
end=None, # 날짜 범위의 끝
periods=3, # 생성할 Period 개수
freq='2H') # 기간의 길이(H: 시간)
#### 날짜 데이터 분리
- 연-월-일 데이터에서 일부를 분리하여 추출
df_stock['Year'] = df_stock['new_Date'].dt.year
df_stock['Month'] = df_stock['new_Date'].dt.month
df_stock['Day'] = df_stock['new_Date'].dt.day
df_stock.head()
# 데이터프레임의 다양한 응용
- 데이터프레임에 함수를 매핑하는 방법, 데이터를 집계하는 그룹연산, 데이터프레임을 합치거나 다양한 구조로 변경하는 방법
## 함수 매핑
- 데이터프레임의 개별 원소를 특정 함수에 일대일 대응시키는 과정
- 사용자 지정 함수를 적용할 수 있기 때문에 판다스 기본 함수로 처리하기 어려운 복잡한 연산을 데이터프레임 등 판다스 객체에 적욯하는 것이 가능
### 개별 원소에 함수 매핑
#### 시리즈 원소에 함수 매핑
- 시리즈 객체에 apply() 메서드를 적용하면 인자로 전달하는 매핑 함수에 시리즈의 모든 함수를 하나씩 입력하고 함수의 리턴값을 반환
- 시리즈의 원소 개수만큼 리턴값을 받아서 같은 크기의 시리즈 객체로 반환
#### 데이터프레임 원소에 함수 매핑
- applymap() 메서드
- 데이터프레임의 개별 원소에 특정 함수를 매핑
### 시리즈 객체에 함수 매핑
#### 데이터프레임의 각 컬럼에 함수 매핑
- apply(axis=0) 메서드
- 데이터프레임 전체에 적용, 개별 값에 함수 적용
- 시리즈를 입력받고 시리즈를 반환하는 함수를 매핑하면 데이터프레임을 반환
- 축을 따라 함수를 적용하는 메서드
- axis=0은 행에 동작하는 거 아닌가?
- 함수가 행에 적용하는데 왜 컬럼에 매핑되는거지?
- axis=0 means “apply function to each column, with the rows changing”
- axis=0 : 행을 변경하면서 각 컬럼에 함수를 적용
- -> 함수를 컬럼에 적용하는 거였다
- -> 그럼 왜 axis=0 이라고 쓰지?
- axis 는 축을 나타낸다
- 행을 축으로-> 눕혀진 책이 쌓이는 형태
- 진행방향이 열=위아래로 움직임 컬럼에 함수를 적용하기 때문
- -> axis 값과 진행방향이 반대라고 생각하면 편하다
사용자 함수 정의
def missing_values(series): # 시리즈를 인수로 전달
return series.isnull() # 불린 시리즈를 반환
데이터프레임의 각 컬럼(시리즈)를 인수로 전달하면 데이터프레임을 반환
result = df.apply(missing_values, axis=0)
result
- 시리즈를 입력받아서 하나의 값을 반환하는 함수를 매핑하면 시리즈를 반환
- axis=0 옵션의 경우 따로 설정하지 않으면 0으로 기본 적용
#### 데이터프레임의 각 행에 함수 매핑
- apply(axis=1) 메서드 적용하면 각 행을 매핑함수의 인자로 전달
- axis=1 : 컬럼을 변경하면서 각 행에 기능을 적용
- 컬럼을 축으로 위아래로 움직이며 행에 함수를 매핑
- 행 인덱스가 매핑 결과로 반환되는 시리즈 인덱스가 됨
데이터프레임 2개 열을 선택하여 적용
x=df, a=df['age'], b=df['ten']
df['add'] = df.apply(lambda x: add_two_obj(x['age'], x['ten']), axis=1)
df.head()
### 데이터프레임 객체에 함수 매핑
- 데이터프레임 객체를 함수에 매핑하려면 pipe() 메서드 활용
- **사용하는 함수가 반환하는 리턴값**에 따라 pipe() 메서드가 반환하는 객체의 종류가 결정됨
- DataFrame을 리턴하는 함수 매핑 -> DataFrame 반환
- Series를 리턴하는 함수 매핑 -> Series 반환
- 값을 리턴하는 함수 매핑 -> 값 반환
데이터프레임 전달해서 데이터프레임 반환
def missing_value(x):
return x.isnull()
데이터프레임 전달해서 시리즈 반환
def missing_count(x):
return missing_value(x).sum()
시리즈 전달해서 값 반환
def total_number_missing(x):
return missing_count(x).sum()
pipe 메서드 매핑
result_df = df.pipe(missing_values)
result_df.head()
### 열 순서 변경
- 데이터프레임의 컬럼 순서를 변경하는 방법
- 컬럼 이름을 원하는 순서대로 정리해서 리스트를 만들고 기존 데이터프레임에서 컬럼을 다시 선택하는 방식으로 가능
컬럼 이름 리스트 만들기
기존 컬럼명
columns = list(df.columns.values)
컬럼명 알파벳 정렬
columns_sorted = sorted(columns)
df_sorted = df[columns_sorted]
기존 순서의 역순 정렬
columns_reversed = list(reversed(columns))
df_reversed = df[columns_reversed]
사용자 정의 순서로 재배치
columns_customed = ['pclass', 'sex', 'age', 'survived']
df_customed = df[columns_customed]
### 열 분리
- 하나의 컬럼이 여러 정보를 담고 있을 때 각 정보를 분리
df['연월일'].dt.year
df['연'] = df['연월일'].dt.year
df['월'] = df['연월일'].dt.month
df['일'] = df['연월일'].dt.day
연산할 게 아니라면 dt.year로 분리하지 않아도 됨
df['연월일'] = df['연월일'].astype('str')
dates = df['연월일'].str.split('-')
- get() 메서드를 활용해 dates 변수에 저장된 문자열 리스트의 원소를 선택
- 각 원소 리스트의 인덱스를 활용해 연, 월, 일 데이터를 따로 선택할 수 있음
df['연'] = dates.str.get(0)
df['월'] = dates.str.get(1)
df['일'] = dates.str.get(2)
## 필터링
- 시리즈 또는 데이터프레임의 데이터 중에서 특정 조건식을 만족하는 원소만 추출
### 불린 인덱싱
- 시리즈 객체에 어떤 조건식을 적용하면 각 원소에 대해 참/거짓을 판별해 불린값으로 구성된 시리즈를 반환
- 참인 데이터값을 따로 선택할 수 있음
- 엑셀의 필터 기능과 동일
- 데이터프레임의 각 컬럼은 시리즈 객체이므로 조건식(<, >, =<, >=, !=, ==)을 적용하면 각 원소가 조건을 만족하는지 여부를 참/거짓 값으로 표시해 불린 시리즈를 만들 수 있음
titanic = sns.load_dataset('titanic')
10대 승객만 선택
mask1 = (titanic.age >= 10) & (titanic.age < 20)
mask1[:10]
& |
mask3 = (titanic['age'] < 10) | (titanic['age'] >= 60)
df_un10_mo60 = titanic.loc[mask3, ['age', 'sex', 'alone']]
df_un10_mo60.head()
### .isin( ) 메서드 활용
- 특정 값을 가진 행들을 따로 추출할 수 있음
mask3 = titanic['sibsp'] == 3
mask4 = titanic['sibsp'] == 4
mask5 = titanic['sibsp'] == 5
df_boolean = titanic[mask3 | mask4 | mask5]
isin_filter = titanic['sibsp'].isin([3,4,5])
df_isin = titanic[isin_filter]
'데이터분석 공부 > DSBA 4기' 카테고리의 다른 글
18/03/24 TIL 분류 성능 평가 지표(정확도, 오차행렬, 정밀도, 재현율, F1 스코어) (0) | 2024.03.18 |
---|---|
03/15/2024 TIL (0) | 2024.03.15 |
iloc loc Value Error 정리 (0) | 2024.03.11 |
파이썬 데이터프레임 특정 문자 포함된 행 삭제하기 / str.replace() 추천하지 않는 경우 (0) | 2024.03.09 |
파이썬 데이터프레임 astype( ) 으로 데이터 자료형 변경하기 (0) | 2024.03.08 |