Chapter03 "데이터 정제하기"
데이터 정제란 데이터에서 손상되거나 부정확한 부분을 수정하고, 불필요한 데이터를 삭제하거나 불완전한 값을 교체하는 등의 작업이다.
Chapter 03도 2개로 나누어 글을 작성하려 한다.
Chapter 03-1의 주제는 '불필요한 데이터 삭제하기' 이다.
03-1 불필요한 데이터 삭제하기
열 삭제하기
먼저 남산도서관 데이터를 가져온다.
# gdown으로 다운로드
import gdown
gdown.download('https://bit.ly/3RhoNho','ns_202104.csv',quiet=False)
# 판다스로 저장
import pandas as pd
ns_df = pd.read_csv('ns_202104.csv',low_memory=False)
ns_df.head()
보면 맨 오른쪽 열이 'Unnamed: 13'이다. csv파일 각 라인 끝에 콤마(,)가 있어서 판다스가 자동으로 추가한 것이다.
불필요하기 때문에 삭제한다.
# 2주차에서 배운 loc메서드에 슬라이싱 사용
ns_book = ns_df.loc[:,'번호':'등록일자']
ns_book.head()
loc 메서드와 불리언 배열
# 데이터프레임의 열 이름이 저장된 columns 속성
print(ns_df.columns)
- columns 속성은 판다스의 Index 클래스 객체
- 객체의 원소는 숫자 인덱스로 참조 가능
# 숫자 인덱스
print(ns_df.columns[0])
결과는 '번호'이다.
Index 클래스를 비롯해 판다스 배열 성격의 객체는 어떤 값과 비교할 때 배열의 원소와 하나씩 비교해주는 원소별 비교를 한다.
원소별 비교를 하면 다음과 같다.
# 원소별 비교 'Unnamed: 13'열이 아닌 배열 생성
ns_df.columns != 'Unnamed: 13'
이를 이용해 전의 슬라이싱을 이용하지 않고 열을 제거할 수 있다.
# 원소별 비교로 열 제거
selected_columns = ns_df.columns !='Unnamed: 13'
ns_book = ns_df.loc[:, selected_columns]
ns_book.head()
drop() 메서드
- 데이터프레임의 행이나 열을 삭제하는 메서드이다.
- 열 삭제를 할 때는 axis 매개변수 = 1로 지정한다.
# ns_df 'Unnamed: 13' 열 삭제
ns_book = ns_df.drop('Unnamed: 13',axis = 1)
ns_book.head()
# 여러 열 삭제시에는 리스트 형식 사용
ns_book = ns_df.drop(['부가기호','Unnamed: 13'],axis = 1)
ns_book.head()
- inplace 매개변수 : 새 변수에 저장하지 않고 덮어쓰기
# implace 매개변수
ns_book.drop('주제분류번호',axis = 1,inplace = True)
ns_book.head()
dropna() 메서드
- 판다스는 빈 값을 NaN으로 표시한다
- NaN이 포함된 열이나 행 삭제하는 메서드이다
# NaN이 포함된 열 삭제
ns_book = ns_df.dropna(axis = 1)
ns_book.head()
# 모든 값이 NaN인 열 삭제: how 매개변수
ns_book = ns_df.dropna(axis = 1, how = 'all')
ns_book.head()
행 삭제하기
- drop() 메서드를 사용해도 된다
- 기본값이 axis = 0이다. 행 삭제를 의미한다
# 처음 2개 행 삭제
ns_book2 = ns_book.drop([0,1])
ns_book2.head()
[ ]연산자와 슬라이싱
## 1
# 0, 1행 제외
ns_book2 = ns_book[2:]
ns_book2.head()
## 2
# 슬라이싱 주의: 마지막 값은 포함하지 않는다
ns_book2 = ns_book[0:2]
ns_book2.head()
[ ]연산자와 불리언 배열
# 출판사가 '한빛미디어'인 행만 가져오기
selected_rows = ns_df['출판사'] == '한빛미디어'
ns_book2 = ns_book[selected_rows]
ns_book2.head()
# 불리언 배열을 []연산자 안에 바로 넣기 : 대출건수가 1000이하인 행 삭제
ns_book2 = ns_book[ns_book['대출건수'] > 1000 ]
ns_book2.head()
중복된 행 찾기
- duplicated() 메서드사용
- duplicated() 메서드 : 중복된 행 중에서 처음 행을 제외한 나머지를 True 중복 아니면 False
# 중복된 행 찾기
sum(ns_book.duplicated())
결과는 0이다. '번호' 열이 고유해서 중복이 나올 수 없기 때문이다.
그래서 subset 매개변수로 기준 열을 지정해준다.
# subset 매개변수로 기준 열 지정
sum(ns_book.duplicated(subset = ['도서명','저자','ISBN']))
바뀐 기준 열로 중복된 행을 확인해본다
- keep 메개변수 : False로 지정해주면 중복된 행을 모두 True로 지정
# keep 매개변수로 중복된 행을 모두 True로 지정
dup_rows = ns_book.duplicated(subset = ['도서명','저자','ISBN'], keep = False)
ns_book3 = ns_book[dup_rows]
ns_book3.head()
그룹별로 모으기
- groupby() 메서드 사용
- by 매개변수 : 행을 합칠 때 기준이 되는 열 지정
# 데이터프레임 합치기 : '도서명','저자','ISBN','권'
count_df = ns_book[['도서명','저자','ISBN','권','대출건수']]
group_df = count_df.groupby(by = ['도서명','저자','ISBN','권'],dropna = False)
loan_count = group_df.sum()
# 메서드 이어 쓰기 : groupby와 sum
loan_count = count_df.groupby(by = ['도서명','저자','ISBN','권'],dropna = False).sum()
loan_count.head()
원본 데이터 업데이트하기
업데이트하기 전 거쳐야할 과정
- duplicated() 메서드로 중복된 행을 True로 표시한 불리언 배열을 만듦
- 1번에서 구한 불리언 배열을 반전시켜서 중복되지 않은 고유한 행을 True로 표시
- 2번에서 구한 불리언 배열을 사용해 원본 배열에서 고유한 행만 선택
- 중복된 행을 True로 표시한 불리언 배열을 반전 : ~ 연산자 사용
- 그 후 고유한 배열로 copy() 메서드로 새로 df를 만듦
dup_rows = ns_book.duplicated(subset=['도서명','저자','ISBN','권']) # 중복된 행 True
unique_rows = ~dup_rows # 반전 -> 고유한 행 True
ns_book3 = ns_book[unique_rows].copy() # 고유한 행만 선택
# 중복이 없는지 확인
sum(ns_book3.duplicated(subset=['도서명','저자','ISBN','권']))
원본 데이터프레임 인덱스 설정하기
- set_index()로 지정한 열을 인덱스로 설정
- inplace 매개변수를 True : 새 데이터프레임 반환이 아닌 원래 것을 수정한다
ns_book3.set_index(['도서명','저자','ISBN','권'], inplace = True)
ns_book3.head()
업데이트하기: update() 메서드
# 다른 데이터프레임을 사용해 원본 데이터프레임의 값 업데이트
ns_book3.update(loan_count)
ns_book3.head()
# 인덱스 해제
ns_book4 = ns_book3.reset_index()
ns_book4.head()
- 중복된 도서의 대출건수 합침
# ns_book
sum(ns_book['대출건수']>100)
# ns_book4
sum(ns_book4['대출건수']>100)
차례대로 2311, 2550의 결과가 나온다. 중복된 도서의 대출건수를 합쳐서 늘어났다.
하지만 인덱스를 만들고 해제해서 열 순서가 다르다. 이를 []를 사용해 조정한다.
ns_book4 = ns_book4[ns_book.columns]
ns_book4.head()
일괄 처리 함수 만들기
- 열 삭제
- loc 메서드+슬라이싱+불리언 배열
- drop 메서드
- 행 삭제
- [ ]연산자+슬라이싱+불리언 배열
- 중복된 행 찾기
- groupby 메서드+sum 메서드
- update() 메서드
- set_index()와 reset_index()
def data_cleaning(filename):
"""
남산 도서관 장서 CSV 데이터 전처리 함수
:param filename: CSV 파일 이름
"""
# 파일을 DF로 읽기
ns_df = pd.read_csv(filename, low_memory = False)
# NaN인 열을 삭제
ns_book = ns_df.dropna(axis = 1, how = 'all')
# 대출건수를 합치기 위해 필요한 행만 추출하여 count_df 데이터프레임 생성
count_df = ns_book[['도서명','저자','ISBN','권','대출건수']]
# '도서명','저자','ISBN','권'을 기준으로 대출건수를 groupby
loan_count = count_df.groupby(by=['도서명','저자','ISBN','권'],dropna=False).sum()
# 원본 데이터프레임에서 중복된 행을 제외하고 고유한 행만 추출하여 복사
dup_rows = ns_book.duplicated(subset=['도서명','저자','ISBN','권'])
unique_rows = ~dup_rows
ns_book3 = ns_book[unique_rows].copy()
# '도서명','저자','ISBN','권'을 인덱스로 설정
ns_book3.set_index(['도서명','저자','ISBN','권'], inplace = True)
# loan_count에 저장된 누적 대출건수를 업데이트
ns_book3.update(loan_count)
# 인덱스 재설정
ns_book4 = ns_book3.reset_index()
# 원본 데이터프레임의 열 순서로 변경
ns_book4 = ns_book4[ns_book.columns]
return ns_book4
new_ns_book4 = data_cleaning('ns_book4.csv')
ns_book4.equals(new_ns_book4)
https://colab.research.google.com/drive/1IMSJjbG8LIoNKMp93s6bpQ2oeKYe60wU?usp=sharing
'Data Analysis > 혼공학습단9기' 카테고리의 다른 글
혼자 공부하는 데이터 분석 with 파이썬: 4주차(Chapter 04-1) (0) | 2023.02.19 |
---|---|
혼자 공부하는 데이터 분석 with 파이썬: 3주차(Chapter 03-2) (0) | 2023.01.26 |
혼자 공부하는 데이터 분석 with 파이썬: 2주차(Chapter 02-2) (0) | 2023.01.15 |
혼자 공부하는 데이터 분석 with 파이썬 : 2주차(Chapter 02-1) (0) | 2023.01.11 |
혼자 공부하는 데이터 분석 with 파이썬 : 1주차(Chapter 01) (0) | 2023.01.08 |