데이터 전처리
자료형 변환
- 데이터 타입 확인
# 숫자가 문자열로 저장되어 있다면 숫자로 변환 => 수치형 변수
# 데이터 자료형
df.dtypes
- 문자열 고유값 확인
# 어떤 문자열이 들어갔는지 확인하는 방법
df['horsepower'].unique()
- 문자열 NaN으로 변경
import numpy as np
# ? => NaN
df['horsepower'].replace("?", np.nan, inplace = True) # ? 문자열을 nan으로 변경
df['horsepower'].unique()
- NaN 행 삭제 - dropna
# NaN 행 삭제
df.dropna(subset = 'horsepower', axis = 0, inplace = True)
df['horsepower'].unique()
- 문자열 타입 변경 - astype
# 문자열을 숫자로 변환
df['horsepower'] = df['horsepower'].astype('float')
# 숫자를 범주형으로 변환
df['origin'] = df['origin'].astype('category')
df['origin'].dtypes
구간 분할- cut
- 범주형 변환
# 범주형 변환
bins_name = ["저출력", "중간출력", "고출력"]
df['hp_cat'] = pd.cut(x = df['horsepower'], # 데이터 = 사용할 열
bins = bins, # 구간의 값
labels = bins_name, # 구간의 이름
include_lowest = True) # 구간의 시작값 포함
더미 변수
- 더미 변수는 0 또는 1의 값을 가짐
- 더미 변수 개수 = 그룹의 개수 - 1
- 판다스 - get_dummies
hp_dm = pd.get_dummies(df['hp_cat'])
print(df['hp_cat'])
print(hp_dm)
- 사이킷런 - LabelEncoding
# 사이킷런으로 더미변수 만들기
from sklearn import preprocessing
# 전처리 엔코더 객체
label_encoder = preprocessing.LabelEncoder()
onehot_encoder = preprocessing.OneHotEncoder()
# 문자열 범주를 숫자 범주로 변환 = LabelEncoder
labels = label_encoder.fit_transform(df['hp_cat'])
print(df['hp_cat'][:15])
print(labels[:15])
# 고출력 - 보통출력 - 저출력(글자 순서대로 정렬)
# 0 - 1 - 2
------------------------------------------------------------------
0 보통출력
1 보통출력
2 보통출력
3 보통출력
4 보통출력
5 고출력
6 고출력
7 고출력
8 고출력
9 고출력
10 고출력
11 보통출력
12 보통출력
13 고출력
14 저출력
Name: hp_cat, dtype: category
Categories (3, object): ['저출력' < '보통출력' < '고출력']
[1 1 1 1 1 0 0 0 0 0 0 1 1 0 2]
- 배열 변환 - reshape
# 1차원 배열을 2차원 배열로 변환 => 392개의 행과 1개의 열
labels.reshape(len(labels), 1)
# 모든 행 = -1
reshaped = labels.reshape(**-1**, 1)
- 사이킷런 - OneHot Encoding
# 원-핫 엔코딩
# 희소행렬 = (행, 열) & 값(1)
# 0 숫자 열 = 고출력, 1 숫자 열 = 보통 출력, 2 숫자 열 = 저출력
# (14, 2) 1.0 => 행 인덱스 번호 14에서 2 라는 숫자(저출력) 가지고 있는 열의 값이 1
# = 14번 행의 값은 저출력
oh = onehot_encoder.fit_transform(reshaped)
정규화
- 숫자 데이터의 상대적 크기 차이 제거
- 데이터 값을 동일한 크기 기준으로 나눈 비율로 나타낸 것 = 정규화
- 최대절대값 정규화
# 최대절대값 정규화
# = 관측치 / 절대값(최대값)
# 양수와 음수가 섞여있다면, => 관측치 / 관측치의 절대값의 최대값
# 음수 - 관측치 = - 최대값 => -1
# 양수 - 관측치 = + 최대값 => 1
# -1 ~ 1 사이의 값을 가짐
hp_nmz1 = df['horsepower'] / abs(df['horsepower']).max()
# hp_nmz1 = df['horsepower'] / abs(df['horsepower'].max())
hp_nmz1.describe()
- 최대, 최소값 정규화
# 최소값 - 최대값 정규화
# = (관측치 - 최소값) / (최대값 - 최소값)
# 관측치 = 최소값 => 0
# 관측치 = 최대값 => 1
# 0 ~ 1 사이의 값을 가짐
hp_nmz2 = (df['horsepower'] - df['horsepower'].min()) / (df['horsepower'].max() - df['horsepower'].min())
hp_nmz2.describe()
시계열 데이터
- Timestamp : 특정한 시점을 기록
- Period : 두 시점 사이의 일정한 기간
시계열 객체로 변환
# 1) Timestamp로 먼저 변환해야 함
dates_ts = pd.to_datetime(dates)
# 2) Period 로 변환
dates_ts.to_period(freq = 'D') # 연월일
dates_ts.to_period(freq = 'M') # 연월
dates_ts.to_period(freq = 'A') # 연
# Timestamp 배열 = range()
sd_ts = pd.date_range(start = '2022-01-01', # 시작 날짜
end = None, # 끝 날짜
periods = 12, # Timestamp 개수
freq = 'M', # 월 간격, 월 마지막일
tz = 'Asia/Seoul' # timezone 시간대 설정
)
sd_ts
# freq = 'M' # 월 간격, 월 마지막일
# freq = '3M' # 3개월 간격, 월 마지막일
-----------------------------------------------------------
DatetimeIndex(['2022-01-01 00:00:00+09:00', '2022-02-01 00:00:00+09:00',
'2022-03-01 00:00:00+09:00', '2022-04-01 00:00:00+09:00',
'2022-05-01 00:00:00+09:00', '2022-06-01 00:00:00+09:00',
'2022-07-01 00:00:00+09:00', '2022-08-01 00:00:00+09:00',
'2022-09-01 00:00:00+09:00', '2022-10-01 00:00:00+09:00',
'2022-11-01 00:00:00+09:00', '2022-12-01 00:00:00+09:00'],
dtype='datetime64[ns, Asia/Seoul]', freq='MS')
# Period 배열
sd_prd = pd.date_range(start = '2022-01-01', # 시작 날짜
end = None, # 끝 날짜
periods = 6, # Period 개수 + 1 = 날짜 개수
freq = 'M') # 월 간격
print(sd_prd)
------------------------------------------------------------
DatetimeIndex(['2022-01-31', '2022-02-28', '2022-03-31', '2022-04-30',
'2022-05-31', '2022-06-30', '2022-07-31', '2022-08-31',
'2022-09-30', '2022-10-31', '2022-11-30', '2022-12-31'],
dtype='datetime64[ns]', freq='M')
날짜 데이터 분리
# Timestamp
# 연 - 월 - 일 데이터에서 연, 월, 일 추출
print(df['Date_new'].dt.year) # 연 추출
df['Date_new'].dt.month) # 월 추출
print(df['Date_new'].dt.day) # 일 추출
# Period
print(df['Date_new'].dt.to_period(freq = 'A')) # 연
print(df['Date_new'].dt.to_period(freq = 'M')) # 월
날짜 인덱스로 인덱싱
df['2018'] # 연 => 2018년 데이터들만 추출됨
df['2018-06'] # 2018년 6월 데이터 추출됨
df.loc['2018-06', 'High': 'Low' ] # 연월 & High 열부터 Low 열까지
7. 데이터프레임 응용
개별 원소에 함수 매핑
- apply : 시리즈 원소에 함수 매핑
# 사용자 정의 함수
# 5를 더하는 함수
def add5(x):
return x + 5
# 두 객체를 더하는 함수
def add_two(a, b):
return a + b
df['age'].apply(add5)
df['age'].apply(add_two, b = 3) # a : age, b = 3
df['age'].apply(lambda x: x + 5)
df['age'].apply(lambda x: add5(x))
df['age'].apply(lambda x: add_two(x, b = 3))
- applymap : 데이터프레임 원소에 함수 매핑
df.applymap(add5)
print(df.applymap(lambda x : x + 5))
print(df.applymap(lambda x : add5(x)))
시리즈 객체에 함수 매핑
- apply(매핑함수, axis = 0)
# 1) 반환하는 값이 여러 개인 경우
# 널값에 대한 불 인덱스를 반환하는 함수
def mv_find(series):
return series.isnull()
# 열 단위 = 시리즈 객체
df.apply(mv_find, axis = 0)
---------------------------------------------------------------
# 2) 반환하는 값이 하나인 경우
# 범위를 구하는 함수
def range_xy(series):
return series.max() - series.min()
# 열 단위 = 시리즈 객체
df.apply(range_xy, axis = 0)
# 행 단위
df['age_plus_five'] = df.apply(lambda x : x['age'] + x['five'], axis = 1)
df.apply(lambda x : add_two(x['age'], x['five']), axis = 1)


데이터프레임 객체에 함수 매핑
- pipe(매핑 함수)
df = df.loc[:, 'age' : 'fare']
df1 = df.pipe(mv_find)
# 데이터프레임 = 함수 적용된 결과는 시리즈 개수와 일치 (= 891개)
def mv_count(series):
return mv_find(series).sum()
# 시리즈 = 함수 적용된 결과가 하나(열마다) = 열 개수
df2 = df.pipe(mv_count)
df2
----------------------------------------------------------------
age 177
fare 0
dtype: int64
def mv_count_total(series):
return mv_count(series).sum()
# 개별값 = 함수 적용된 결과가 개별값(전체가) = 전체가 하나
df3 = df.pipe(mv_count_total)
df3
----------------------------------------------------------------
177
데이터 전처리
자료형 변환
- 데이터 타입 확인
# 숫자가 문자열로 저장되어 있다면 숫자로 변환 => 수치형 변수
# 데이터 자료형
df.dtypes
- 문자열 고유값 확인
# 어떤 문자열이 들어갔는지 확인하는 방법
df['horsepower'].unique()
- 문자열 NaN으로 변경
import numpy as np
# ? => NaN
df['horsepower'].replace("?", np.nan, inplace = True) # ? 문자열을 nan으로 변경
df['horsepower'].unique()
- NaN 행 삭제 - dropna
# NaN 행 삭제
df.dropna(subset = 'horsepower', axis = 0, inplace = True)
df['horsepower'].unique()
- 문자열 타입 변경 - astype
# 문자열을 숫자로 변환
df['horsepower'] = df['horsepower'].astype('float')
# 숫자를 범주형으로 변환
df['origin'] = df['origin'].astype('category')
df['origin'].dtypes
구간 분할- cut
- 범주형 변환
# 범주형 변환
bins_name = ["저출력", "중간출력", "고출력"]
df['hp_cat'] = pd.cut(x = df['horsepower'], # 데이터 = 사용할 열
bins = bins, # 구간의 값
labels = bins_name, # 구간의 이름
include_lowest = True) # 구간의 시작값 포함
더미 변수
- 더미 변수는 0 또는 1의 값을 가짐
- 더미 변수 개수 = 그룹의 개수 - 1
- 판다스 - get_dummies
hp_dm = pd.get_dummies(df['hp_cat'])
print(df['hp_cat'])
print(hp_dm)
- 사이킷런 - LabelEncoding
# 사이킷런으로 더미변수 만들기
from sklearn import preprocessing
# 전처리 엔코더 객체
label_encoder = preprocessing.LabelEncoder()
onehot_encoder = preprocessing.OneHotEncoder()
# 문자열 범주를 숫자 범주로 변환 = LabelEncoder
labels = label_encoder.fit_transform(df['hp_cat'])
print(df['hp_cat'][:15])
print(labels[:15])
# 고출력 - 보통출력 - 저출력(글자 순서대로 정렬)
# 0 - 1 - 2
------------------------------------------------------------------
0 보통출력
1 보통출력
2 보통출력
3 보통출력
4 보통출력
5 고출력
6 고출력
7 고출력
8 고출력
9 고출력
10 고출력
11 보통출력
12 보통출력
13 고출력
14 저출력
Name: hp_cat, dtype: category
Categories (3, object): ['저출력' < '보통출력' < '고출력']
[1 1 1 1 1 0 0 0 0 0 0 1 1 0 2]
- 배열 변환 - reshape
# 1차원 배열을 2차원 배열로 변환 => 392개의 행과 1개의 열
labels.reshape(len(labels), 1)
# 모든 행 = -1
reshaped = labels.reshape(**-1**, 1)
- 사이킷런 - OneHot Encoding
# 원-핫 엔코딩
# 희소행렬 = (행, 열) & 값(1)
# 0 숫자 열 = 고출력, 1 숫자 열 = 보통 출력, 2 숫자 열 = 저출력
# (14, 2) 1.0 => 행 인덱스 번호 14에서 2 라는 숫자(저출력) 가지고 있는 열의 값이 1
# = 14번 행의 값은 저출력
oh = onehot_encoder.fit_transform(reshaped)
정규화
- 숫자 데이터의 상대적 크기 차이 제거
- 데이터 값을 동일한 크기 기준으로 나눈 비율로 나타낸 것 = 정규화
- 최대절대값 정규화
# 최대절대값 정규화
# = 관측치 / 절대값(최대값)
# 양수와 음수가 섞여있다면, => 관측치 / 관측치의 절대값의 최대값
# 음수 - 관측치 = - 최대값 => -1
# 양수 - 관측치 = + 최대값 => 1
# -1 ~ 1 사이의 값을 가짐
hp_nmz1 = df['horsepower'] / abs(df['horsepower']).max()
# hp_nmz1 = df['horsepower'] / abs(df['horsepower'].max())
hp_nmz1.describe()
- 최대, 최소값 정규화
# 최소값 - 최대값 정규화
# = (관측치 - 최소값) / (최대값 - 최소값)
# 관측치 = 최소값 => 0
# 관측치 = 최대값 => 1
# 0 ~ 1 사이의 값을 가짐
hp_nmz2 = (df['horsepower'] - df['horsepower'].min()) / (df['horsepower'].max() - df['horsepower'].min())
hp_nmz2.describe()
시계열 데이터
- Timestamp : 특정한 시점을 기록
- Period : 두 시점 사이의 일정한 기간
시계열 객체로 변환
# 1) Timestamp로 먼저 변환해야 함
dates_ts = pd.to_datetime(dates)
# 2) Period 로 변환
dates_ts.to_period(freq = 'D') # 연월일
dates_ts.to_period(freq = 'M') # 연월
dates_ts.to_period(freq = 'A') # 연
# Timestamp 배열 = range()
sd_ts = pd.date_range(start = '2022-01-01', # 시작 날짜
end = None, # 끝 날짜
periods = 12, # Timestamp 개수
freq = 'M', # 월 간격, 월 마지막일
tz = 'Asia/Seoul' # timezone 시간대 설정
)
sd_ts
# freq = 'M' # 월 간격, 월 마지막일
# freq = '3M' # 3개월 간격, 월 마지막일
-----------------------------------------------------------
DatetimeIndex(['2022-01-01 00:00:00+09:00', '2022-02-01 00:00:00+09:00',
'2022-03-01 00:00:00+09:00', '2022-04-01 00:00:00+09:00',
'2022-05-01 00:00:00+09:00', '2022-06-01 00:00:00+09:00',
'2022-07-01 00:00:00+09:00', '2022-08-01 00:00:00+09:00',
'2022-09-01 00:00:00+09:00', '2022-10-01 00:00:00+09:00',
'2022-11-01 00:00:00+09:00', '2022-12-01 00:00:00+09:00'],
dtype='datetime64[ns, Asia/Seoul]', freq='MS')
# Period 배열
sd_prd = pd.date_range(start = '2022-01-01', # 시작 날짜
end = None, # 끝 날짜
periods = 6, # Period 개수 + 1 = 날짜 개수
freq = 'M') # 월 간격
print(sd_prd)
------------------------------------------------------------
DatetimeIndex(['2022-01-31', '2022-02-28', '2022-03-31', '2022-04-30',
'2022-05-31', '2022-06-30', '2022-07-31', '2022-08-31',
'2022-09-30', '2022-10-31', '2022-11-30', '2022-12-31'],
dtype='datetime64[ns]', freq='M')
날짜 데이터 분리
# Timestamp
# 연 - 월 - 일 데이터에서 연, 월, 일 추출
print(df['Date_new'].dt.year) # 연 추출
df['Date_new'].dt.month) # 월 추출
print(df['Date_new'].dt.day) # 일 추출
# Period
print(df['Date_new'].dt.to_period(freq = 'A')) # 연
print(df['Date_new'].dt.to_period(freq = 'M')) # 월
날짜 인덱스로 인덱싱
df['2018'] # 연 => 2018년 데이터들만 추출됨
df['2018-06'] # 2018년 6월 데이터 추출됨
df.loc['2018-06', 'High': 'Low' ] # 연월 & High 열부터 Low 열까지
7. 데이터프레임 응용
개별 원소에 함수 매핑
- apply : 시리즈 원소에 함수 매핑
# 사용자 정의 함수
# 5를 더하는 함수
def add5(x):
return x + 5
# 두 객체를 더하는 함수
def add_two(a, b):
return a + b
df['age'].apply(add5)
df['age'].apply(add_two, b = 3) # a : age, b = 3
df['age'].apply(lambda x: x + 5)
df['age'].apply(lambda x: add5(x))
df['age'].apply(lambda x: add_two(x, b = 3))
- applymap : 데이터프레임 원소에 함수 매핑
df.applymap(add5)
print(df.applymap(lambda x : x + 5))
print(df.applymap(lambda x : add5(x)))
시리즈 객체에 함수 매핑
- apply(매핑함수, axis = 0)
# 1) 반환하는 값이 여러 개인 경우
# 널값에 대한 불 인덱스를 반환하는 함수
def mv_find(series):
return series.isnull()
# 열 단위 = 시리즈 객체
df.apply(mv_find, axis = 0)
---------------------------------------------------------------
# 2) 반환하는 값이 하나인 경우
# 범위를 구하는 함수
def range_xy(series):
return series.max() - series.min()
# 열 단위 = 시리즈 객체
df.apply(range_xy, axis = 0)
# 행 단위
df['age_plus_five'] = df.apply(lambda x : x['age'] + x['five'], axis = 1)
df.apply(lambda x : add_two(x['age'], x['five']), axis = 1)
데이터프레임 객체에 함수 매핑
- pipe(매핑 함수)
df = df.loc[:, 'age' : 'fare']
df1 = df.pipe(mv_find)
# 데이터프레임 = 함수 적용된 결과는 시리즈 개수와 일치 (= 891개)
def mv_count(series):
return mv_find(series).sum()
# 시리즈 = 함수 적용된 결과가 하나(열마다) = 열 개수
df2 = df.pipe(mv_count)
df2
----------------------------------------------------------------
age 177
fare 0
dtype: int64
def mv_count_total(series):
return mv_count(series).sum()
# 개별값 = 함수 적용된 결과가 개별값(전체가) = 전체가 하나
df3 = df.pipe(mv_count_total)
df3
----------------------------------------------------------------
177
'Python' 카테고리의 다른 글
[python] 문자열 변환_함수 format( ) (0) | 2023.06.12 |
---|---|
[Python][한국복지패널데이터] 주제 1_성별에 따른 월급 차이 (0) | 2023.06.08 |
[python] 데이터 전처리 - 널값 처리 (0) | 2023.06.01 |
[python] 데이터 시각화 (0) | 2023.06.01 |
[Python] raw string (0) | 2023.05.18 |