오늘은 데이터 전처리에 대해서 배우고 현업에서는 어떤 방식으로 전처리를 진행하고 편하게 할 수 있는 팁들을 배워보았다.
apt['지역코드'] # 생략
apt.loc[:, '지역코드'] # 원형
apt[['지역코드', '거래금액']] # 생략
apt.loc[:, ['지역코드', '거래금액']] # 원형
apt.loc[:, ['거래금액', '지역코드', '아파트']]
apt.loc[:, '거래금액':'아파트']
특정 타입 컬럼만 선택
dtypes사용
apt.loc[:, apt.dtypes == 'int64']
apt.loc[:, (apt.dtypes == 'int64') | (apt.dtypes == 'float64')]
select_dtypes 사용exclude : 필요 없는 클래스 지정 가능apt.select_dtypes(include=[int, float])
특정 문자열 포함 컬럼만 선택
str.contains사용
- 파이프(|)는 정규 표현식에서 or를 의미하는 메타문자
apt.loc[:, apt.columns.str.contains(pat='년|월|일')]
sr.str[index] : 각 원소를 대괄호 안에 지정한 인덱스로 인덱싱sr.str.split(pat) : 각 원소를 패턴으로 분리한 리스트를 시리즈로 반환sr.str.contains(pat) : 각 원소에서 패턴의 존재 여부를 불리언 시리즈로 반환sr.str.replace(pat, repl) : 패턴에 맞는 문자열을 repl에 지정한 문자열로 변경regex 매개변수에 True 지정sr.str.extract(pat) : 패턴에 맞는 첫 번째 문자열을 데이터프레임으로 반환sr.str.extractall(pat) : 패턴에 맞는 모든 문자열을 데이터프레임으로 반환| 구분 | 상세 내용 | 구분 | 상세 내용 |
|---|---|---|---|
‘.’ | 줄바꿈을 제외한 모든 문자(공백 포함) | ‘[a-z]’ | 알파벳 소문자(26개) |
‘\\w’ | 알파벳 대소문자, 숫자, 언더바, 한글 | ‘[A-Z]’ | 알파벳 대문자(26개) |
‘\\d’ | 숫자 | ‘[0-9]’ | 숫자(10개) |
‘\\s’ | 공백, ‘\r\n’ (줄바꿈), ‘\t’ (탭) | ‘[ㄱ-ㅎ]’ | 한글 단자음, 쌍자음, 겹자음(30개) |
‘\\W’ | ‘\\w’ 의 반대 | ‘[ㅏ-ㅣ]’ | 한글 단모음, 이중모음(21개) |
‘\\D’ | ‘\\d’ 의 반대 | ‘[가-힣]’ | 한글 완성형(11,172개) |
‘\\S’ | ‘\\s’ 의 반대 | ‘[一-龥]’ | 한자(20,902개) |
| `‘ | ’` | 문자열을 or로 지정 | ‘[^가-힣]’ |
‘+’ | 앞 패턴이 1~∞ 연속 일치 | ‘\\b’ | 단어의 경계 여부 검사(단어 경계) |
‘*’ | 앞 패턴이 0~∞ 연속 일치 | ‘\\B’ | ‘\\b' 의 반대(비단어 경계) |
‘?’ | 앞 패턴이 0 또는 1번 일치 | ‘()’ | 일치하는 패턴 저장(캡처링 그룹) |
‘{n}’ | 앞 패턴이 정확하게 n번 연속 일치 | ‘(?:)’ | 패턴 저장하지 않음(비캡처링 그룹) |
‘{n,m}’ | 앞 패턴이 n~m번 연속 일치(n < m) | ‘\\n’ | n번째 캡처링 그룹 재탐색(역참조) |
‘{n,}’ | 앞 패턴이 n~∞ 연속 일치 | ‘A(?=B)’ | B 앞에 오는 A 패턴 매칭(긍정 전방탐색) |
‘\’ | 메타문자의 기능 해제(이스케이프) | ‘(?≤A)B’ | A 뒤에 오는 B 패턴 매칭(긍정 후방탐색) |
‘^’ | 문자열의 시작 위치 고정(앵커) | ‘A(?!B)’ | ?= 의 반대(부정 전방탐색) |
‘$’ | 문자열의 끝 위치 고정(앵커) | ‘(?<!A)B’ | ?<= 의 반대(부정 후방탐색) |
nums = pd.Series(data=['M:010-2345-6789', 'T:02-345-6789', 'ID:001231-7890123'])
nums.str[0]
# 0 M
# 1 T
# 2 I
# dtype: object
nums.str[0:2]
# 0 M:
# 1 T:
# 2 ID
# dtype: object
nums.str.extract(pat='(M|T|ID)')
nums.str.extract(pat='([A-Z]+)')
# 0
# 0 M
# 1 T
# 2 ID
nums.str.split(pat=':')
# 0 [M, 010-2345-6789]
# 1 [T, 02-345-6789]
# 2 [ID, 001231-7890123]
# dtype: object
nums.str.split(pat=':|-')
# 0 [M, 010, 2345, 6789]
# 1 [T, 02, 345, 6789]
# 2 [ID, 001231, 7890123]
# dtype: object
nums.str.split(pat=':|-', expand=True)
# 0 1 2 3
# 0 M 010 2345 6789
# 1 T 02 345 6789
# 2 ID 001231 7890123 None
str.extract는 실행 결과로 항상 데이터프레임을 반환nums.str.extract(pat='([0-9]+)')
# 0
# 0 010
# 1 02
# 2 001231
nums.str.extract(pat='(-[0-9]+-)')[0].str.replace(pat='-', repl='')
# 0 2345
# 1 345
# 2 NaN
# Name: 0, dtype: object
nums.str.extract(pat='((?<=-)[0-9]+(?=-))')[0]
cond = apt['거래금액'] >= 1500000
apt.loc[cond, :]
cond = (apt['거래금액'] <= 1500000) & (apt['층'] >= 65)
apt.loc[cond, :]
| 구분 | 상세 내용 |
|---|---|
sr.gt(other=value) | sr 원소가 value 초과면 True, 아니면 False인 불리언 시리즈 반환(sr > value) |
sr.ge(other=value) | sr 원소가 value 이상이면 True, 아니면 False인 불리언 시리즈 반환(sr ≥ value) |
sr.lt(other=value) | sr 원소가 value 미만이면 True, 아니면 False인 불리언 시리즈 반환(sr < value) |
sr.le(other=value) | sr 원소가 value 이하면 True, 아니면 False인 불리언 시리즈 반환(sr ≤ value) |
sr.eq(other=value) | sr 원소가 value 같으면 True, 아니면 False인 불리언 시리즈 반환(sr == value) |
sr.ne(other=value) | sr 원소가 value 다르면 True, 아니면 False인 불리언 시리즈 반환(sr ≠ value) |
cond = apt['거래금액'].lt(1500000) & apt['층'].ge(65)
apt.loc[cond, :]
between() 사용isclusive 매개변수 : 양쪽 경계 포함 여부 ‘both’, ‘neither’, ‘left’, ‘right’cond = apt['층'].ge(10) & apt['층'].le(20)
apt.loc[cond, :].shape # (88699, 15)
cond = apt['층'].between(10, 20)
apt.loc[cond, :].shape # (88699, 15)
isin())cond = apt['시군구'].eq('강남구')
apt.loc[cond, :].shape # (12790, 15)
cond = apt['시군구'].eq('강남구') | apt['시군구'].eq('서초구')
apt.loc[cond, :].shape # (23526, 15)
cond_1 = apt['시군구'].eq('강남구')
cond_2 = apt['시군구'].eq('서초구')
apt.loc[cond_1 | cond_2, :].shape # (23526, 15)
cond = apt['시군구'].eq('강남구') | apt['시군구'].eq('서초구') | apt['시군구'].eq('송파구')
apt.loc[cond, :].shape # (37970, 15)
cond_1 = apt['시군구'].eq('강남구')
cond_2 = apt['시군구'].eq('서초구')
cond_3 = apt['시군구'].eq('송파구')
apt.loc[cond_1 | cond_2 | cond_3, :].shape # (37970, 15)
isin : 원소가 리스트에 있으면 True, 아니면 Falsecond = apt['시군구'].isin(['강남구', '서초구', '송파구'])
apt.loc[cond, :].shape # (37970, 15)
str.contains + 정규 표현식cond = apt['시군구'].str.contains(pat='^강')
apt.loc[cond, :].shape # (44193, 15)
apt = apt.drop(columns=['지역코드', '매도자'])
apt1.drop(index=[163874, 220404])
apt1.index[0:2]
apt1.drop(index=apt1.index[0:2])
rename())‘기존이름’: ‘새이름’ 구조columns 매개변수 생략Xapt.rename(columns={
'아파트': '단지명',
'건축년도': '입주년도'
})
columns 로 열 조회 후 열이름 일괄 변경apt.columns
apt.columns = ['거래금액', '단지명', '시도명', '시군구', '법정동', '지번', '입주년도', '계약년도', '계약월', '계약일', '등기일자',
'전용면적', '층']
set_index(), reset_index())df2 = df1.set_index(['아파트', '시도명', '시군구', '법정동', '지번'])
reset_index() : 인덱스 초기화drop=True : 기존 인덱스 제거df1.reset_index(drop=True)
apt['평당금액'] = apt['거래금액'] / apt['전용면적'] * 3.3
apt['거래금액'] = apt['거래금액'] / 10000
apt['경과년수'] = apt['계약년도'] - apt['입주년도']
np.where())# for문으로 구간화
imsi = apt.copy()
result = []
for i in apt['경과년수']:
if i >= 30:
result.append('충족')
else:
result.append('부족')
imsi = imsi.assign(재건축 = result)
imsi.head()
np.where() : 조건, True일 때 반환값, False일 때 반환값 지정cond = apt['경과년수'].ge(30)
apt['재건축'] = np.where(cond, '충족', '부족')
cond = apt['경과년수'].ge(30)
np.where(cond)[0]
np.select(), pd.cut(), pd.qcut())np.selectcondlist : 조건의 리스트choicelist : 조건에 따른 반환 값default : 모든 조건을 만족하지 못할 때 반환 값np.select(
condlist=[
apt['경과년수'].le(5),
apt['경과년수'].le(10),
apt['경과년수'].gt(10)
],
choicelist=['신축', '준신축', '구축'],
default='0'
)
pd.cutbins : 경계를 지정(연속형 변수의 최솟값과 최댓값을 미리 확인)apt['경과년수'].min()
apt['경과년수'].max()
pd.cut(
x=apt['경과년수'],
bins=[-2, 5, 10, 62],
labels=['신축', '준신축', '구축']
)
pd.qcut : q 값에 따라 분할pd.qcut(
x=apt['경과년수'],
q=3,
labels=['신축', '준신축', '구축']
)
sr.astype(class) : 시리즈의 자료형 변환apt['계약년도'] = apt['계약년도'].astype(str)
apt['계약월'] = apt['계약월'].astype(str)
apt['계약일'] = apt['계약일'].astype(str)
df.astype({col: class}) : 일부 열의 자료형 변환apt = apt.astype(
{
'x1': int,
'x2': str
}
)
df[cols].astype(class) : 전체 열의 자료형 일괄 변환cols = ['x1', 'x2', 'x3', 'x4']
apt[cols] = apt[cols].astype(int)
오늘도 많은 내용을 배웠다. 전처리 파트에 대해서 디테일하게 배우니까 저번 교육에서 배우지 못했던 정보들이 많이 있었다. 그리고 확실히 오늘 배운 내용들을 자유자제로 다룰 수 있게 되면 이후에 많은 도움이 될 것 같다.