호쌤
호쌤 Just For Fun

[Python 데이터 분석] 데이터 전처리

크리에이티브 커먼즈 라이선스 ITPAPER(호쌤,쭈쌤)에 의해 작성된 ≪[Python 데이터 분석] 데이터 전처리≫은(는) 크리에이티브 커먼즈 저작자표시-비영리-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.
이 라이선스의 범위 이외의 이용허락을 얻기 위해서는 leekh4232@gmail.com으로 문의하십시오.

[Python 데이터 분석] 데이터 전처리

데이터 전처리란 데이터를 본격적으로 분석하기 전에 분석에 적합하게 데이터를 가공하는 작업을 의미하는 것으로 데이터 가공(Data Manipulation), 데이터 핸들링(Data Handling)도 비슷한 의미로 사용되는 용어들 입니다.

데이터 전처리에서 수행되는 작업들

  1. 행,열의 순서 변경
  2. 컬럼이나 인덱스의 이름 변경
  3. 데이터 정렬
  4. 데이터 검색
  5. 행, 열 추가
  6. 행, 열 삭제
  7. 두 개 이상의 데이터 프레임 병합하기

#01. 필요한 패키지 참조 및 샘플 데이터 준비하기

1) 패키지 참조하기

1
2
3
4
5
6
import numpy
from pandas import DataFrame  # 데이터프레임 클래스
from pandas import Series     # 시리즈 클래스
from pandas import ExcelFile  # Excel 파일을 읽어들이기 위한 클래스
from pandas import concat     # 행단위 병합기능을 제공하는 함수
from pandas import merge      # 열단위 병합기능을 제공하는 함수

2) 샘플 데이터 준비

1
2
3
xls = ExcelFile('http://itpaper.co.kr/demo/py/grade.xlsx')
성적표 = xls.parse(xls.sheet_names[0])
성적표
▶ 출력결과
이름 학년 성별 국어 영어 수학 과학
0 철수 1 남자 98 NaN 88.0 64.0
1 영희 2 여자 88 90.0 62.0 72.0
2 민수 1 남자 92 70.0 NaN NaN
3 수현 3 여자 63 60.0 31.0 70.0
4 호영 4 남자 120 50.0 NaN 88.0

#02. 행,열의 순서 변경

1) 열 순서 변경하기

지정된 순서대로 이 재정렬 된 결과가 반환된다.

원본은 변화 없고, 결과가 적용된 복사본이 반환된다.

1
2
df1 = 성적표.reindex(columns=['국어','수학','과학','영어', '성별', '학년'])
df1
▶ 출력결과
국어 수학 과학 영어 성별 학년
0 98 88.0 64.0 NaN 남자 1
1 88 62.0 72.0 90.0 여자 2
2 92 NaN NaN 70.0 남자 1
3 63 31.0 70.0 60.0 여자 3
4 120 NaN 88.0 50.0 남자 4

지정되지 않은 컬럼은 제외되기 때문에 원하는 항목을 추출하는 기능을 수행하기도 한다.

1
2
df2 = 성적표.reindex(columns=['이름', '국어','수학','영어'])
df2
이름 국어 수학 영어
0 철수 98 88.0 NaN
1 영희 88 62.0 90.0
2 민수 92 NaN 70.0
3 수현 63 31.0 60.0
4 호영 120 NaN 50.0

2) 인덱스(행) 순서 변경

지정된 순서대로 이 재정렬 된 결과가 반환된다.

원본은 변화 없고, 결과가 적용된 복사본이 생성된다.

1
2
df3 = 성적표.reindex(index=[1,3,2,0,4])
df3
▶ 출력결과
이름 학년 성별 국어 영어 수학 과학
1 영희 2 여자 88 90.0 62.0 72.0
3 수현 3 여자 63 60.0 31.0 70.0
2 민수 1 남자 92 70.0 NaN NaN
0 철수 1 남자 98 NaN 88.0 64.0
4 호영 4 남자 120 50.0 NaN 88.0

컬럼의 경우와 마찬가지로 지정되지 않은 항목은 제외되기 때문에 원하는 행을 추출하는 기능을 수행하기도 한다.

1
2
df4 = 성적표.reindex(index=[0,1,2])
df4
이름 학년 성별 국어 영어 수학 과학
0 철수 1 남자 98 NaN 88.0 64.0
1 영희 2 여자 88 90.0 62.0 72.0
2 민수 1 남자 92 70.0 NaN NaN

3) 행,열 순서를 한번에 변경하기

1
2
3
df5 = 성적표.reindex(columns=['이름','국어','수학','과학','영어'],
                    index=[4,3,2,1,0])
df5
▶ 출력결과
이름 국어 수학 과학 영어
4 호영 120 NaN 88.0 50.0
3 수현 63 31.0 70.0 60.0
2 민수 92 NaN NaN 70.0
1 영희 88 62.0 72.0 90.0
0 철수 98 88.0 64.0 NaN

#03. 컬럼이나 인덱스의 이름 변경

  • “기존이름: 새이름” 형식의 딕셔너리로 지정
  • 원본은 변화 없음. 결과가 적용된 복사본이 생성된다.

inplace=True 파라미터를 지정하면 원본에 바로 반영되고 반환되는 결과값이 없다.

1) 컬럼 이름 변경하기

1
2
df6 = 성적표.rename(columns={'국어':'kor', '영어':'eng', '수학':'math', '과학': 'sinc'})
df6
▶ 출력결과
이름 학년 성별 kor eng math sinc
0 철수 1 남자 98 NaN 88.0 64.0
1 영희 2 여자 88 90.0 62.0 72.0
2 민수 1 남자 92 70.0 NaN NaN
3 수현 3 여자 63 60.0 31.0 70.0
4 호영 4 남자 120 50.0 NaN 88.0

2) 인덱스 이름 변경하기

1
2
df7 = 성적표.rename(index={0: '학생1', 1: '학생2', 2: '학생3'} )
df7
▶ 출력결과
이름 학년 성별 국어 영어 수학 과학
학생1 철수 1 남자 98 NaN 88.0 64.0
학생2 영희 2 여자 88 90.0 62.0 72.0
학생3 민수 1 남자 92 70.0 NaN NaN
3 수현 3 여자 63 60.0 31.0 70.0
4 호영 4 남자 120 50.0 NaN 88.0

3) 특정 컬럼을 인덱스로 변환하기

inplace=Ture옵션은 원본 데이터프레임에 즉시 반영한다.

1
2
성적표.set_index('이름', inplace=True)
성적표
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
철수 1 남자 98 NaN 88.0 64.0
영희 2 여자 88 90.0 62.0 72.0
민수 1 남자 92 70.0 NaN NaN
수현 3 여자 63 60.0 31.0 70.0
호영 4 남자 120 50.0 NaN 88.0

#04. 데이터 정렬

  • rename()함수와 마찬가지로 inplace=True 파라미터를 사용하면 원본에 즉시 반영된다.

1) 특정 열로 오름차순(순차) 정렬

1
2
오름차순 = 성적표.sort_values('국어')
오름차순
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
수현 3 여자 63 60.0 31.0 70.0
영희 2 여자 88 90.0 62.0 72.0
민수 1 남자 92 70.0 NaN NaN
철수 1 남자 98 NaN 88.0 64.0
호영 4 남자 120 50.0 NaN 88.0

2) 특정 열로 내림차순(역순)정렬

1
2
내림차순 = 성적표.sort_values('국어', ascending=False)
내림차순
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
호영 4 남자 120 50.0 NaN 88.0
철수 1 남자 98 NaN 88.0 64.0
민수 1 남자 92 70.0 NaN NaN
영희 2 여자 88 90.0 62.0 72.0
수현 3 여자 63 60.0 31.0 70.0

3) 두 개 이상의 컬럼을 기준으로 정렬하기

1
2
3
4
# 국어 점수가 동일할 경우 수학점수 순으로 정렬된다.
# inpace=True를 사용했으므로 원본에 바로 반영된다.
성적표.sort_values(['국어', '수학'], inplace=True)
성적표
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
수현 3 여자 63 60.0 31.0 70.0
영희 2 여자 88 90.0 62.0 72.0
민수 1 남자 92 70.0 NaN NaN
철수 1 남자 98 NaN 88.0 64.0
호영 4 남자 120 50.0 NaN 88.0

4) 인덱스를 기준으로 정렬하기

순차정렬

1
2
인덱스정렬1 = 성적표.sort_index()
인덱스정렬1
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
민수 1 남자 92 70.0 NaN NaN
수현 3 여자 63 60.0 31.0 70.0
영희 2 여자 88 90.0 62.0 72.0
철수 1 남자 98 NaN 88.0 64.0
호영 4 남자 120 50.0 NaN 88.0

역순정렬, 원본에 반영

1
2
성적표.sort_index(ascending=False, inplace=True)
성적표
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
호영 4 남자 120 50.0 NaN 88.0
철수 1 남자 98 NaN 88.0 64.0
영희 2 여자 88 90.0 62.0 72.0
수현 3 여자 63 60.0 31.0 70.0
민수 1 남자 92 70.0 NaN NaN

#05. 데이터 검색 (조건에 맞는 데이터 추출하기)

1) 행단위 조건 검색

단일 조건

기본적인 비교식을 사용한다.

1
2
# 국어 점수가 90점을 넘는 학생 조회
성적표.query('국어 > 90')
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
호영 4 남자 120 50.0 NaN 88.0
철수 1 남자 98 NaN 88.0 64.0
민수 1 남자 92 70.0 NaN NaN

And 조건 사용

1
성적표.query('국어 > 80 and 수학 > 80')
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
철수 1 남자 98 NaN 88.0 64.0

Or 조건

1
2
# 국어점수가 70점 미만이거나 수학점수가 70점 미만인 학생 조회
성적표.query('국어 < 70 or 수학 < 70')
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
영희 2 여자 88 90.0 62.0 72.0
수현 3 여자 63 60.0 31.0 70.0

in 조건

특정 리스트의 원소중 겹치는 값 찾기
1
2
3
# 검색 조건에 대한 리스트 준비
item = [98, 88]
item
▶ 출력결과
1
[98, 88]
1
2
# 국어점수가 item 리스트에 포함되어 있는 데이터 찾기
성적표.query('국어 in @item')
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
철수 1 남자 98 NaN 88.0 64.0
영희 2 여자 88 90.0 62.0 72.0

not in 조건

특정 리스트의 원소와 겹치지 않는 값 찾기

1
2
# 국어점수가 item 리스트에 포함되지 않는 데이터 찾기
성적표.query('국어 not in @item')
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
호영 4 남자 120 50.0 NaN 88.0
수현 3 여자 63 60.0 31.0 70.0
민수 1 남자 92 70.0 NaN NaN

3) 열단위 필터링

1
2
# 열 필터링 --> 추출할 컬럼의 이름을 리스트로 전달한다.
성적표.filter(['국어','영어'])
▶ 출력결과
국어 영어
이름
호영 120 50.0
철수 98 NaN
영희 88 90.0
수현 63 60.0
민수 92 70.0

#06. 행, 열 추가

1) 행 추가

a) 예제 진행을 위한 데이터 프레임 복사

원본 데이터가 변경될 경우 에러가 발생했을 때 처음부터 다시 실행할 수 없게 되므로 복사본을 만들어놓고 진행하는 것이 좋다.

1
2
3
# 데이터프레임 복제
add_row = 성적표.copy()
add_row
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
호영 4 남자 120 50.0 NaN 88.0
철수 1 남자 98 NaN 88.0 64.0
영희 2 여자 88 90.0 62.0 72.0
수현 3 여자 63 60.0 31.0 70.0
민수 1 남자 92 70.0 NaN NaN

b) 리스트 활용

  • 원본 자체가 수정됨
  • 추가될 행의 인덱스 이름을 지정해 준다.
  • 리스트로 추가할 경우 dataframe의 컬럼 순서에 맞게 지정한다.
  • 누락되는 값이 있거나 값의 수가 초과될 경우 에러
1
2
add_row.loc['영민'] = [3, '남자', 90, 80, 90, 62]
add_row
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
호영 4 남자 120 50.0 NaN 88.0
철수 1 남자 98 NaN 88.0 64.0
영희 2 여자 88 90.0 62.0 72.0
수현 3 여자 63 60.0 31.0 70.0
민수 1 남자 92 70.0 NaN NaN
영민 3 남자 90 80.0 90.0 62.0

c) 딕셔너리를 사용한 행 추가

  • 컬럼의 순서는 상관 없다.
  • 누락되는 값이 있거나 값의 수가 초과될 경우 에러
  • 빈 값을 적용해야 하는 경우 None 이라고 지정한다. (따옴표 사용 안함)
1
2
add_row.loc['민정'] = {'국어': 81, '영어': 72, '과학': 90, '수학': 84, '성별': '여자', '학년': 2}
add_row
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
호영 4 남자 120 50.0 NaN 88.0
철수 1 남자 98 NaN 88.0 64.0
영희 2 여자 88 90.0 62.0 72.0
수현 3 여자 63 60.0 31.0 70.0
민수 1 남자 92 70.0 NaN NaN
영민 3 남자 90 80.0 90.0 62.0
민정 2 여자 81 72.0 84.0 90.0

d) 기존의 행을 복사하여 추가하기

1
2
add_row.loc['철민'] = add_row.loc['철수']
add_row
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
호영 4 남자 120 50.0 NaN 88.0
철수 1 남자 98 NaN 88.0 64.0
영희 2 여자 88 90.0 62.0 72.0
수현 3 여자 63 60.0 31.0 70.0
민수 1 남자 92 70.0 NaN NaN
영민 3 남자 90 80.0 90.0 62.0
민정 2 여자 81 72.0 84.0 90.0
철민 1 남자 98 NaN 88.0 64.0

e) 다른 데이터 프레임과 병합

제외된 열에 대해서는 NaN(결측치)로 설정됨

1
2
3
# sort: 열을 이름순으로 정렬함(기본값 true)
tmp = DataFrame({'국어': 81, '수학': 84, '과학': 90}, index=["상호"])
tmp
▶ 출력결과
국어 수학 과학
상호 81 84 90

A.append(B) 명령은 A에 B를 덧붙인다는 의미.

이 경우는 컬럼의 쌍이 맞지 않더라도 병합 가능하다. 존재하지 않는 컬럼의 경우 None으로 저장된다.

sort 파라미터에 대한 경고가 표시될 경우 무시해도 무관하다.

1
2
append_row = add_row.append(tmp)
append_row
1
2
3
4
5
6
7
8
c:\users\ezen\appdata\local\programs\python\python37\lib\site-packages\pandas\core\frame.py:6692: FutureWarning: Sorting because non-concatenation axis is not aligned. A future version
of pandas will change to not sort by default.

To accept the future behavior, pass 'sort=False'.

To retain the current behavior and silence the warning, pass 'sort=True'.

  sort=sort)
과학 국어 성별 수학 영어 학년
호영 88.0 120 남자 NaN 50.0 4.0
철수 64.0 98 남자 88.0 NaN 1.0
영희 72.0 88 여자 62.0 90.0 2.0
수현 70.0 63 여자 31.0 60.0 3.0
민수 NaN 92 남자 NaN 70.0 1.0
영민 62.0 90 남자 90.0 80.0 3.0
민정 90.0 81 여자 84.0 72.0 2.0
철민 64.0 98 남자 88.0 NaN 1.0
상호 90.0 81 NaN 84.0 NaN NaN

2) 열 추가

a) 예제 진행을 위한 데이터 프레임 복사

1
2
add_col = 성적표.copy()
add_col
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
호영 4 남자 120 50.0 NaN 88.0
철수 1 남자 98 NaN 88.0 64.0
영희 2 여자 88 90.0 62.0 72.0
수현 3 여자 63 60.0 31.0 70.0
민수 1 남자 92 70.0 NaN NaN

b) 리스트를 활용한 열 추가

리스트 형식으로 추가할 경우 행의 수에 맞게 추가되어야 한다.

1
2
add_col['한국사'] = [92, 83, 72, None, 80]
add_col
▶ 출력결과
학년 성별 국어 영어 수학 과학 한국사
이름
호영 4 남자 120 50.0 NaN 88.0 92.0
철수 1 남자 98 NaN 88.0 64.0 83.0
영희 2 여자 88 90.0 62.0 72.0 72.0
수현 3 여자 63 60.0 31.0 70.0 NaN
민수 1 남자 92 70.0 NaN NaN 80.0

c) 단일 값 추가

새로운 열에 하나의 값을 지정하면 모든 행이 동일한 값을 갖는다.

1
2
add_col['세계사'] = 100
add_col
▶ 출력결과
학년 성별 국어 영어 수학 과학 한국사 세계사
이름
호영 4 남자 120 50.0 NaN 88.0 92.0 100
철수 1 남자 98 NaN 88.0 64.0 83.0 100
영희 2 여자 88 90.0 62.0 72.0 72.0 100
수현 3 여자 63 60.0 31.0 70.0 NaN 100
민수 1 남자 92 70.0 NaN NaN 80.0 100

d) Serise를 통한 열 추가

각 값이 연결될 행의 이름(index)를 지정해야 한다. 부분적으로 값을 비워 둘 수 있다.

여기서는 호영의 데이터가 생략되었고, 민철은 원본 데이터에 존재하지 않기 때문에 추가되지 않는다.

1
2
add_col['사회'] = Series([82, 90, 92, 64, 77], index=['철수', '영희', '민철', '수현', '민수'])
add_col
▶ 출력결과
학년 성별 국어 영어 수학 과학 한국사 세계사 사회
이름
호영 4 남자 120 50.0 NaN 88.0 92.0 100 NaN
철수 1 남자 98 NaN 88.0 64.0 83.0 100 82.0
영희 2 여자 88 90.0 62.0 72.0 72.0 100 90.0
수현 3 여자 63 60.0 31.0 70.0 NaN 100 64.0
민수 1 남자 92 70.0 NaN NaN 80.0 100 77.0

e) 조건에 따른 선택적인 값을 추가

조건이 참인 경우 A, 그렇지 않은 경우 B
1
2
add_col['국어결과'] = numpy.where(add_col['국어'] >= 70, '합격', '불합격')
add_col
▶ 출력결과
학년 성별 국어 영어 수학 과학 한국사 세계사 사회 국어결과
이름
호영 4 남자 120 50.0 NaN 88.0 92.0 100 NaN 합격
철수 1 남자 98 NaN 88.0 64.0 83.0 100 82.0 합격
영희 2 여자 88 90.0 62.0 72.0 72.0 100 90.0 합격
수현 3 여자 63 60.0 31.0 70.0 NaN 100 64.0 불합격
민수 1 남자 92 70.0 NaN NaN 80.0 100 77.0 합격

f) 여러 개의 조건중에서 선택적인 값을 추가하기

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 학점을 부여하기 위한 점수의 구간을 설정하는 조건들을 리스트로 설정
conditions = [
                (add_col['영어'] >= 90),   # A
                (add_col['영어'] >= 80),   # B
                (add_col['영어'] >= 70)    # C
             ]

# 조건에 따라 부여될 학점
grade = [ 'A', 'B', 'C' ]

# 조건에 따른 학점열 추가하기
# default 파라미터는 조건에 부합하지 않을 경우 사용할 기본값
add_col['영어학점'] = numpy.select(conditions, grade, default='F')
add_col
▶ 출력결과
학년 성별 국어 영어 수학 과학 한국사 세계사 사회 국어결과 영어학점
이름
호영 4 남자 120 50.0 NaN 88.0 92.0 100 NaN 합격 F
철수 1 남자 98 NaN 88.0 64.0 83.0 100 82.0 합격 F
영희 2 여자 88 90.0 62.0 72.0 72.0 100 90.0 합격 A
수현 3 여자 63 60.0 31.0 70.0 NaN 100 64.0 불합격 F
민수 1 남자 92 70.0 NaN NaN 80.0 100 77.0 합격 C

#07. 행, 열 삭제

1) 행 삭제

a) 예제 진행을 위한 데이터 프레임 복사

1
2
del_row = 성적표.copy()
del_row
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
호영 4 남자 120 50.0 NaN 88.0
철수 1 남자 98 NaN 88.0 64.0
영희 2 여자 88 90.0 62.0 72.0
수현 3 여자 63 60.0 31.0 70.0
민수 1 남자 92 70.0 NaN NaN

b) 특정 행 삭제하기

행 삭제는 원본에 반영되지 않고 결과가 적용된 새로운 데이터프레임이 반환된다.

1
2
d1 = del_row.drop('철수')
d1
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
호영 4 남자 120 50.0 NaN 88.0
영희 2 여자 88 90.0 62.0 72.0
수현 3 여자 63 60.0 31.0 70.0
민수 1 남자 92 70.0 NaN NaN

c) 여러 행 삭제하기

리스트 형태로 행의 이름을 파라미터로 전달한다.

존재하지 않는 행을 삭제하고자 할 경우 에러가 발생한다.

1
2
d2 = del_row.drop(['호영','영희'])
d2
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
철수 1 남자 98 NaN 88.0 64.0
수현 3 여자 63 60.0 31.0 70.0
민수 1 남자 92 70.0 NaN NaN

d) 인덱스 번호를 통한 특정 위치의 행 삭제

1
2
3
# 0번째행 삭제
d3 = del_row.drop(del_row.index[0])
d3
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
철수 1 남자 98 NaN 88.0 64.0
영희 2 여자 88 90.0 62.0 72.0
수현 3 여자 63 60.0 31.0 70.0
민수 1 남자 92 70.0 NaN NaN

e) 인덱스 번호를 통한 범위 내의 행 삭제하기

1
2
d4 = del_row.drop(del_row.index[1:4])
d4
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
호영 4 남자 120 50.0 NaN 88.0
민수 1 남자 92 70.0 NaN NaN

f) 삭제 결과를 원본에 반영하기

drop 함수에 inplace=True 파라미터를 추가하면 원본 자체에서 삭제된다.

1
2
del_row.drop(['영희','수현'], inplace=True)
del_row
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
호영 4 남자 120 50.0 NaN 88.0
철수 1 남자 98 NaN 88.0 64.0
민수 1 남자 92 70.0 NaN NaN

2) 열 삭제

drop() 함수에 axis=1 파라미터를 추가한다.

  • axis=0: x축, 행에 대한 적용, 기본값
  • axis=1: y축, 열에 대한 적용, Optional

inplace=True를 적용하지 않는다면 삭제 결과가 반영된 결과값이 리턴된다.

예제 진행을 위한 데이터프레임 복사

1
2
del_col = 성적표.copy()
del_col
▶ 출력결과
학년 성별 국어 영어 수학 과학
이름
호영 4 남자 120 50.0 NaN 88.0
철수 1 남자 98 NaN 88.0 64.0
영희 2 여자 88 90.0 62.0 72.0
수현 3 여자 63 60.0 31.0 70.0
민수 1 남자 92 70.0 NaN NaN

a) 컬럼 이름을 통한 열 삭제

1
2
k1 = del_col.drop('국어', axis=1)
k1
▶ 출력결과
학년 성별 영어 수학 과학
이름
호영 4 남자 50.0 NaN 88.0
철수 1 남자 NaN 88.0 64.0
영희 2 여자 90.0 62.0 72.0
수현 3 여자 60.0 31.0 70.0
민수 1 남자 70.0 NaN NaN

b) 여러 열을 동시에 삭제하기

열 이름을 리스트로 지정

1
2
k2 = del_col.drop(['영어', '수학', '과학'], axis=1)
k2
▶ 출력결과
학년 성별 국어
이름
호영 4 남자 120
철수 1 남자 98
영희 2 여자 88
수현 3 여자 63
민수 1 남자 92

c) 인덱스 번호를 활용한 열 삭제

1
2
k3 = del_col.drop(del_col.columns[3], axis=1)
k3
▶ 출력결과
학년 성별 국어 수학 과학
이름
호영 4 남자 120 NaN 88.0
철수 1 남자 98 88.0 64.0
영희 2 여자 88 62.0 72.0
수현 3 여자 63 31.0 70.0
민수 1 남자 92 NaN NaN

c) 인덱스 번호를 활용하여 지정된 범위만큼 삭제

1
2
k4 = del_col.drop(del_col.columns[1:3], axis=1)
k4
▶ 출력결과
학년 영어 수학 과학
이름
호영 4 50.0 NaN 88.0
철수 1 NaN 88.0 64.0
영희 2 90.0 62.0 72.0
수현 3 60.0 31.0 70.0
민수 1 70.0 NaN NaN

#08. 두 개 이상의 데이터 프레임 병합하기

1) 행단위 병합

a) 샘플 DataFrame 만들기

  • df_top과 df_middle은 국어 컬럼이 동일하다.
  • df_top과 df_bottom은 민철 인덱스가 동일하다.
1
2
df_top = DataFrame({'국어': [90, 82], '수학': [81, 76]}, index=['민철', '철수'])
df_top
▶ 출력결과
국어 수학
민철 90 81
철수 82 76
1
2
df_middle = DataFrame({'국어': [70, 62], '영어': [77, 68]}, index=['영민', '정수'])
df_middle
국어 영어
영민 70 77
정수 62 68
1
2
df_bottom = DataFrame({'영어': [70, 88], '과학': [81, 76]}, index=['민철', '태영'])
df_bottom
영어 과학
민철 70 81
태영 88 76

b) A에 B를 이어 붙이기

  • 단순히 세로로 병합만 수행한다.
  • 데이터프레임간에 컬럼이 다르더라도 존재하지 않는 컬럼은 빈값(결측치)로 채워 넣는다.
1
2
3
# df_top에 연결할 대상이 두 개 이상이라면 파라미터를 리스트로 구분.
df_a = df_top.append([df_middle, df_bottom])
df_a
▶ 출력결과
과학 국어 수학 영어
민철 NaN 90.0 81.0 NaN
철수 NaN 82.0 76.0 NaN
영민 NaN 70.0 NaN 77.0
정수 NaN 62.0 NaN 68.0
민철 81.0 NaN NaN 70.0
태영 76.0 NaN NaN 88.0

c) A, B, C를 병합하기

append()함수와 동일한 결과

  • 단순히 세로 방향으로 덧붙이는 개념이므로 인덱스가 중복되는 경우도 발생한다.

Pandas 버전에 따라 sort 파라미터에 대한 경고 메시지가 표시될 수 있다. 무시해도 좋다.

1
2
df_b = concat([df_top, df_middle, df_bottom])
df_b
▶ 출력결과
과학 국어 수학 영어
민철 NaN 90.0 81.0 NaN
철수 NaN 82.0 76.0 NaN
영민 NaN 70.0 NaN 77.0
정수 NaN 62.0 NaN 68.0
민철 81.0 NaN NaN 70.0
태영 76.0 NaN NaN 88.0

2) 열단위 병합

한 번에 두 개의 데이터프레임만 병합 가능함

a) 인덱스가 지정되지 않은 샘플 데이터 프레임 만들기

1
2
df_left = DataFrame({'고객번호': [1001, 1002, 1003, 1004], '이름': ['철수', '영희', '민철', '미영']})
df_left
▶ 출력결과
고객번호 이름
0 1001 철수
1 1002 영희
2 1003 민철
3 1004 미영
1
2
df_right = DataFrame({'고객번호': [1001, 1002, 1003, 1005], '금액': [10000, 20000, 15000, 5000]})
df_right
고객번호 금액
0 1001 10000
1 1002 20000
2 1003 15000
3 1005 5000

b) 두 데이터프레임의 공통 컬럼을 기준으로 병합하기

양쪽 데이터프레임에 모두 존재하는 데이터만 보여준다.

Database의 Inner Join과 같은 개념

1
2
3
4
# 병합시 제외되는 항목들
# - df_left의 고객번호 1004번 데이터는 df_right의 고객번호 컬럼과 겹치지 않는다.
# - df_right의 고객번호 1005번 데이터는 df_left의 고객번호 컬럼과 겹치지 않는다.
merge(df_left, df_right)
▶ 출력결과
고객번호 이름 금액
0 1001 철수 10000
1 1002 영희 20000
2 1003 민철 15000

c) 왼쪽 데이터프레임을 기준으로 오른쪽 프레임을 병합하기

how='left' 파라미터는 왼쪽 DataFrame의 모든 데이터를 보여준다.

Database의 Left Outer Join과 같은 개념

1
2
# df_right의 고객번호 1005은 df_left에 존재하지 않기 때문에 병합되지 않는다.
merge(df_left, df_right, how='left')
▶ 출력결과
고객번호 이름 금액
0 1001 철수 10000.0
1 1002 영희 20000.0
2 1003 민철 15000.0
3 1004 미영 NaN

d) 오른쪽 데이터프레임을 기준으로 왼쪽 프레임을 병합하기

how=’right’ 파라미터는 오른쪽 DataFrame의 모든 데이터를 보여준다.

Database의 Right Outer Join과 같은 개념

1
2
# df_left의 고객번호 1004는 df_right에 존재하지 않기 때문에 병합되지 않는다.
merge(df_left, df_right, how='right')
▶ 출력결과
고객번호 이름 금액
0 1001 철수 10000
1 1002 영희 20000
2 1003 민철 15000
3 1005 NaN 5000

e) 양쪽 DataFrame을 모두 병합하기

how='outer' 파라미터를 추가하면 공통 컬럼의 값이 한쪽에만 있어도 데이터를 보여준다.

Database의 Full Outer Join과 같은 개념

1
merge(df_left, df_right, how='outer')
▶ 출력결과
고객번호 이름 금액
0 1001 철수 10000.0
1 1002 영희 20000.0
2 1003 민철 15000.0
3 1004 미영 NaN
4 1005 NaN 5000.0

f) 중복되는 데이터가 존재하는 경우의 열단위 병합

모든 경우의 수를 따져서 조합을 만들어 낸다.

1
2
df_first = DataFrame({'아이디': ['hello', 'world', 'python', 'hello'], '결재금액': [14000, 13000, 15000, 13000]})
df_first
▶ 출력결과
아이디 결재금액
0 hello 14000
1 world 13000
2 python 15000
3 hello 13000
1
2
df_second = DataFrame({'아이디': ['hello', 'python', 'python', 'world'], '적립금': [300, 500, 100, 200]})
df_second
아이디 적립금
0 hello 300
1 python 500
2 python 100
3 world 200
1
merge(df_first, df_second)
아이디 결재금액 적립금
0 hello 14000 300
1 hello 13000 300
2 world 13000 200
3 python 15000 500
4 python 15000 100

g) 공통 컬럼이 두 개 이상 존재하는 경우의 병합

두 데이터프레임에서 이름이 같은 열은 모두 키가 된다.
1
2
3
4
df_a = DataFrame({'고객명': ['민수', '수영'],
                  '데이터': ['20000', '100000'],
                  '날짜': ['2018-01-01', '2018-01-01']})
df_a
▶ 출력결과
고객명 데이터 날짜
0 민수 20000 2018-01-01
1 수영 100000 2018-01-01
1
2
df_b = DataFrame({'고객명': ['민수', '수영'], '데이터': ['21세', '20세']})
df_b
고객명 데이터
0 민수 21세
1 수영 20세
merge 처리하기

고객컬럼과 데이터컬럼이 동시에 일치하는 데이터를 찾아 병합한다.

존재하지 않으므로 결과 없음

1
merge(df_a, df_b)
▶ 출력결과
고객명 데이터 날짜
on 파라미터를 사용하여 기준 열 지정하기

df_a의 데이터는 금액을 의미하지만 df_b의 데이터는 나이를 의미하므로 병합의 기준으로 사용되어서는 안된다.

기준 열이 아니면서 이름이 같은 열에는 _x 또는 _y 와 같은 접미사가 붙는다.

1
2
merge_tmp = merge(df_a, df_b, on=['고객명'])
merge_tmp
▶ 출력결과
고객명 데이터_x 날짜 데이터_y
0 민수 20000 2018-01-01 21세
1 수영 100000 2018-01-01 20세
컬럼이름을 수정하여 최종 결과 만들기
1
2
merge_result = merge_tmp.rename(columns={"데이터_x": "금액", "데이터_y": "나이"})
merge_result
▶ 출력결과
고객명 금액 날짜 나이
0 민수 20000 2018-01-01 21세
1 수영 100000 2018-01-01 20세

h) 공통 컬럼이 존재하지 않는 경우의 병합

left_on, right_on 파라미터를 사용하여 병합의 기준이 되는 열 이름을 명시해야 한다.

1
2
국어점수 = DataFrame({'이름': ['영희', '철수'], '국어': [87, 91]})
국어점수
▶ 출력결과
이름 국어
0 영희 87
1 철수 91
1
2
영어점수 = DataFrame({'성명': ['영희', '철수'], '영어': [90, 82]})
영어점수
성명 영어
0 영희 90
1 철수 82
왼쪽의 이름 컬럼과 오른쪽의 성명 컬럼이 같은 데이터를 병합
1
2
국어영어 = merge(국어점수, 영어점수, left_on=['이름'], right_on=['성명'])
국어영어
▶ 출력결과
이름 국어 성명 영어
0 영희 87 영희 90
1 철수 91 철수 82
중복되는 값을 갖는 성명컬럼은 필요 없으므로 삭제
1
2
국어영어.drop('성명', axis=1, inplace=True)
국어영어
▶ 출력결과
이름 국어 영어
0 영희 87 90
1 철수 91 82

i) 인덱스를 기준으로 하는 병합

left_index=True, right_index=True 파라미터를 선택적으로 사용한다.

1
2
수학점수 = DataFrame({'수학': [90, 82]}, index=['민철', '봉구'])
수학점수
▶ 출력결과
수학
민철 90
봉구 82
1
2
과학점수 = DataFrame({'과학': [90, 82]}, index=['민철', '철수'])
과학점수
과학
민철 90
철수 82
index를 기준으로 하기

양쪽 데이터 프레임의 인덱스가 같은 행끼리 병합됨

1
2
수학과학 = merge(수학점수, 과학점수, left_index=True, right_index=True)
수학과학
▶ 출력결과
수학 과학
민철 90 90
인덱스가 겹치지 않더라도 병합하도록 how 파라미터 적용
1
2
수학과학 = merge(수학점수, 과학점수, left_index=True, right_index=True, how='outer')
수학과학
▶ 출력결과
수학 과학
민철 90.0 90.0
봉구 82.0 NaN
철수 NaN 82.0

j) 왼쪽의 인덱스와 오른쪽의 컬럼을 기준으로 병합하기

1
2
한국사 = DataFrame({'한국사': [87, 91]}, index=['영희', '철수'])
한국사
▶ 출력결과
한국사
영희 87
철수 91
1
2
세계사 = DataFrame({'세계사': [90, 82], '이름': ['영희', '철수']})
세계사
세계사 이름
0 90 영희
1 82 철수
왼쪽에서는 인덱스 사용, 오른쪽에서는 이름열 사용

인덱스가 사라지고 모두 컬럼으로 지정된다.

1
2
역사점수 = merge(한국사, 세계사, left_index=True, right_on=["이름"])
역사점수
▶ 출력결과
한국사 세계사 이름
0 87 90 영희
1 91 82 철수
이름 컬럼을 인덱스로 지정하기

Pandas DataFrame에서는 인덱스가 그래프 표현에서의 x축을 담당하기 때문에 매우 중요한 역할을 한다고 볼 수 있다.
그러므로 데이터프레임 생성시 인덱스가 부적절하면 적절한 전처리 과정을 거쳐 인덱스를 생성해야 한다.

1
2
역사점수.set_index('이름', inplace=True)
역사점수
▶ 출력결과
한국사 세계사
이름
영희 87 90
철수 91 82
Rating:

크리에이티브 커먼즈 라이선스 ITPAPER(호쌤,쭈쌤)에 의해 작성된 ≪[Python 데이터 분석] 데이터 전처리≫은(는) 크리에이티브 커먼즈 저작자표시-비영리-동일조건변경허락 4.0 국제 라이선스에 따라 이용할 수 있습니다.
이 라이선스의 범위 이외의 이용허락을 얻기 위해서는 leekh4232@gmail.com으로 문의하십시오.

comments powered by Disqus