들어가며
지금까지 배운 파이썬 기초를 베이스로 pandas라이브러리를 이용한 데이터 전처리의 기초적인 부분을 다뤄보자.
파일 탐색
pandas 라이브러리의 `read_csv()`등의 함수를 활용해서 데이터파일을 불러올 수 있다. 파일을 불러오기 위해서는 경로를 지정해줘야 하는데 이 때 절대경로 또는 상대경로를 사용하게 된다.
`/` | root, Window에서는 `C:\` |
`~/` | 사용자 폴더, Window에서는 `C:\Users\사용자계정이름` |
`./` | 현재 작업 폴더(working directory), 별도로 작업하지 않은 경우 생략 가능 |
`../` | 현재 폴더의 상위 폴더 |
# 타켓 파일 : test.csv
# 절대 경로
'C:/Users/사용자/Desktop/02_python시각화/data/test.csv'
# 상대 경로(현재 디렉토리 : 02_python시각화)
'./data/test.csv'
CSV 파일 불러오기
CSV는 Comma Separated Values의 약자로 `,`와 `\n`로 구분된 데이터파일을 말한다. pandas의 `read_csv()`함수를 이용하여 파일을 불러오자.
import pandas as pd
df_ins = pd.read_csv("./data/insurance.csv")
df_ins
현재 디렉토리의 data폴더 안에 있는 `insurance.csv` 파일을 읽어서 `df_ins`에 저장한 후 출력한다. 1338개의 행과 7개의 열로 이루어져 있고, 2차원 형태의 테이블로 나타나는 것을 확인할 수 있다.
이렇게 복수의 행과 복수의 열로 이루어져 있는 데이터 타입을 `DataFrame`이라고 한다.
type(df_ins)
# pandas.core.frame.DataFrame
또한 하나의 속성 값들만 있는 데이터 타입을 `Series`라고 한다.
type(df_ins.age)
# pandas.core.frame.DataFrame
아래는 `Series`와 `DataFrame`의 상관관계를 그림으로 표현한 것이다.
데이터 살펴보기
`head()`로 가장 앞에 있는 몇개의 관측치를 확인해볼 수 있다. 초기값이 5이므로 아무런 수를 지정해주지 않으면 5개의 관측치를 제공한다. 그래서 어떤 수를 지정해주면 그 수 만큼 관측치를 제공하는 기능을 가지고 있다.
df_ins.head(10)
반대로 `tatil()`을 이용해서 가장 끝에 있는 몇개의 관측치를 확인해볼 수 있다. 아무런 수를 지정하지 않았기 때문에 가장 끝 5개의 관측치를 제공한 모습이다.
df_ins.tail()
`shape`는 관측치의 개수와 속성의 개수를 튜플형태로 알려준다. 행의 인덱스가 0부터 시작해서 1337까지 있기 때문에 총 개수는 1338로 계산된다. 속성은 예상한대로 7개인 것을 알 수있다. 튜플 형태이기 때문에 0이나 1로 인덱싱해서 하나의 값만 확인할 수도 있다.
df_ins.shape
# (1338, 7)
df_ins.shape[0]
# 1338
`index` 메서드는 행의 이름을 확인할 수 있다. 시작지점(start), 끝지점(stop), 몇계단씩(step)인지 표시해준다. RangeIndex는 데이터 타입을 의미한다. 슬라이싱 개념처럼 stop은 포함하지 않는다.
df_ins.index
# RangeIndex(start=0, stop=1338, step=1)
`columns` 메서드는 속성 이름을 확인할 수 있다. 데이터 타입 `Index`안에 리스트 형태가 있고, 각 속성이름들이 문자열 형태로 나열되어있다.
df_ins.columns
# Index(['age', 'sex', 'bmi', 'children', 'smoker', 'region', 'charges'], dtype='object')
`dtypes` 는 모든 변수의 형식을 확인한다. 여기서 object는 문자열을 의미한다. 중요한 것은 하나의 열은 모두 동일한 데이터타입으로 해석할 수 있어야 한다는 것이다. float값을 갖는 열인데 정수형태의 값이 하나라도 들어있다거나 하면 절대 안된다.
df_ins.dtypes
[참고] encoding 지정 및 index, header 지정
csv파일을 불러오는데 인코딩 방식이 한글을 지원하지 않음으로써 에러가 발생할 수있다. 따라서 한글을 지원하는 encoding방식을 따로 지정해주어야 한다.
# csv 파일의 인코딩 문제
pd.read_csv('./data/고용지표_20221115084415.csv')
# 옵션 encoding='CP949' 추가
pd.read_csv('./data/고용지표_20221115084415.csv', encoding='cp949')
또한 속성이 2행 이상으로 구성되어 있거나, 인덱스 값이 필요없는 경우, 다음과 같이 `read_csv()`의 매개변수를 설정해줄 수 있다.
# index, header 지정
pd.read_csv('./data/고용지표_20221115084415.csv', encoding='CP949', index_col=0, header=[0,1])
인덱스값이 0인 행을 관측치로 인식하고, 왼쪽 인덱스 값이 표시된 상단의 데이터프레임이 하단의 데이터프레임으로
깔끔하게 수정된 모습을 확인할 수 있다.
Excel 파일 불러오기
pandas에서 `read_excel()` 을 이용하여 엑셀 파일을 불러올 수 있다. `read_csv()`와는 다르게 따로 encoding 지정이 없어도 가능하다.
sheet1 = pd.read_excel('./data/test.xlsx')
sheet1
시트 번호를 지정하고 지정한 줄만큼 무시하는 기능을 지원한다.
- `sheet_name` : 시트 이름이나 번호를 지정. 번호는 0부터 시작
- `skiprows` : 무시할 행 수
dic_df = pd.read_excel('./data/test.xlsx', sheet_name=2, skiprows=None)
dic_df
첫 행부터 데이터가 시작되는 경우, 데이터를 불러오면서 변수 이름(속성)을 지정할 수 있다. 여기서 속성 1의 세번째 값이 `-` 로 되어있는데 이 값은 문자열로 간주하여 숫자가 아닌 값이라는 뜻의 `NaN`으로 지정한다.
sheet3 = pd.read_excel('./data/test.xlsx', sheet_name=2, header=None, names=['년도','건수'])
sheet3.dtypes # 건수는 '-'가 있기 때문에 문자열로 지정(결측치)
sheet3.dtypes
데이터 결합
concat()을 활용한 동일 구조 데이터 행 결합
`concat()`으로 동일한 구조의 여러 데이터프레임들을 이어 붙일 수 있다. 먼저 데이터들을 읽어오자. 데이터 파일에 처음 15줄까지는 설명글이 존재하므로 `skiprows=15`로 제외시켜준다. 그리고 한글 지원을 위해 인코딩방식을 `CP949`를 지정한다.
import pandas as pd
dp_apt1 = pd.read_csv('./data/아파트(매매)__실거래가_20210902153616.csv', skiprows=15, encoding='CP949')
dp_apt2 = pd.read_csv('./data/아파트(매매)__실거래가_20210902153636.csv', skiprows=15, encoding='CP949')
dp_apt3 = pd.read_csv('./data/아파트(매매)__실거래가_20210902153655.csv', skiprows=15, encoding='CP949')
display(df_apt1); display(df_apt2); display(df_apt3)
이제 위에서 받은 3개의 `DataFrame`을 `concat()`으로 합쳐서 `df_apt`에 다시 저장한다. 행을 기준으로 합치기 때문에 `axis`옵션에 `0`을 할당한다. 반대로 `1`을 할당하면 열을 기준으로 결합할 수 있다.
df_apt = pd.concat([df_apt1, df_apt2, df_apt3], axis=0) # 인덱스 번호도 그대로 이어져서 붙여짐(중복)
df_apt
실행하면 `386 x 13`의 데이터프레임인데 끝번호가 75인 것을 알 수 있다. 행을 기준으로 붙이기는 했지만 기존의 인덱스 번호도 그대로 붙여졌기 때문에 이러한 결과를 확인할 수 있다.
이런 경우에는 `reset_index()`를 이용해서 기존의 인덱스를 제거하고 새로 부여해줄 수 있다. `inplace`옵션은 원본 데이터프레임의 수정사항을 적용할 지 결정한다. 새로운 인덱스가 부여되면 기존의 인덱스는 사라지지 않고 남아있는데 이 마저도 제거하고자 한다면 `drop`옵션을 지정해줄 수 있다.
df_apt.reset_index(inplace=True) # 반환값이 없음
[참고] glob과 for 반복문을 활용한 복수 데이터 처리
`glob`라이브러리의 `glob()`을 활용하면 복수의 데이터 경로를 손쉽게 처리할 수 있다.
from glob import glob
# 'data/apt/'에 존재하는 모든 csv파일의 경로를 file_list에 저장
file_list = glob('data/apt/*.csv')
target = list()
# file_list에 있는 파일경로들을 불러온 후 target리스트에 추가
for path_ in file_list:
target.append(pd.read_csv(path_, skiprows=15, encoding='CP949'))
# target리스트에 있는 데이터 프레임들을 행을 기준으로 이어붙이고, 새로운 인덱스 부여
df_subway = pd.concat(target, axis=0).reset_index(drop=True)
merge()를 활용한 KEY변수 기준 결합
`KEY`변수를 활용한 데이터 결합은 `merge()`를 활용한다. 결합을 하는 방법은 `how`옵션을 활용해서 어떤 방법으로 지정해줄 수 있다.
`inner` | inner join. key 기준 일치하는 관측치만 포함 |
`left` | left join. inner join의 결과물과 왼쪽 데이터의 짝 없는 관측치 포함 |
`right` | right join. inner join의 결과물과 오른쪽 데이터의 짝 없는 관측치 포함 |
`outer` | full outer join. inner join과 양쪽 데이터의 짝이 없는 모든 관측치 포함 |
어느 데이터프레임을 기준으로 할지, 어떤 방향으로 분석을 할지에 따라서 결합 방법은 다양하게 바꿔가며 사용할 수 있다.
데이터 부분 선택
일반적인 비즈니스 데이터 분석에서 주제와 기간, 사이트, 제품, 공정 등 본인의 업무와 관련이 있는 일부 데이터만 선택하고 활용한다. SQL을 활용한 데이터 추출 과정과 별개로 Python에서 각 분석 과정에서 맞게 부분 데이터를 다시 선택하고 사용할 수 있다.
데이터 프레임의 변수(열 선택 방법)
열을 선택하는 방법은 두가지가 있다. `DataFrame`뒤에 마침표 `.`를 찍고 `Tab`키를 눌러 메서드들과 함께 변수 이름을 선택하는 방법이 있고, `[]`연산자를 활용한 방법이 있다. 만약 열의 이름에 공백이 존재할 경우, 첫번째 방법으로는 사용이 불가하기 때문에 두번째 방법 사용을 권장한다.
# .을 활용한 하나의 변수(열) 선택 (공백이 포함된 변수명일 경우 사용 불가)
df_ins.region # 변수의 이름에 공백이 들어가면 사용이 불가능 ex) df_ins.age of
# (★권장)선택 문법을 통한 열 선택 (공백이 포함된 변수명일 경우에도 사용 가능)
df_ins['region']
대괄호를 활용한 데이터 부분 선택
대괄호를 이용해서 하나의 열을 추출한 경우, 그 데이터타입은 다음과 같이 `Series`라는 것을 알 수있다.
# 한 변수 선택
type(df_ins['age'])
그리고 여러개의 열도 선택할 수 있는데, 대괄호 안에 `,`를 기준으로 선택하면 된다. 주의할 점은 결과에서 표시되는 인덱스는 값일 뿐, 순서를 의미하지 않는 다는 것을 인지하고 있어야 한다.
# 리스트를 활용한 복수 변수 선택
x =['age','smoker','charges']
df_ins[x]
이렇게 연속된 대괄호를 사용해서 열과 행에 조건을 줄 수도 있다.
# 연속된 대괄호 활용가능
x = df_ins[['age','smoker','charges']][0:5] # df[0:5]
x.shape[0]
loc과 iloc을 활용한 관측치/변수 선택
`loc`은 행 이름(index)과 열 이름(column)으로 데이터에서 일부를 선택하고, `iloc`은 정수(integer) 형식의 행 번호, 열 번호를 활용한다. 두 방법 모두 리스트`[ ]`나 슬라이스`:`를 활용한 방법을 지원한다.
실습을 위해 원본 데이터를 복제하고 부분선택한 후, 인덱스를 별도로 지정해줬다.
# 원본 데이터프레임에서 처음 10개의 행 복사
df_ins2 = df_ins.copy()[0:10]
# 101~110 범위의 수를 df_ins2의 'idx'열 값으로 할당
df_ins2['idx'] = list(range(101, 111))
# 'idx'값들을 df_ins2의 인덱스 값으로 세팅
df_ins2.set_index('idx', inplace=True)
loc을 활용한 부분 선택
`loc`은 실제로 눈에 보이는 index와 column을 활용한다. 즉 `loc`에는 순서적인 위치개념이 없다.
# series형태
df_ins2.loc[101]
# 정수형 리스트를 변수에 저장한 후 그 변수를 loc에 지정
x = [101, 103]
df_ins2.loc[x]
# 슬라이싱으로 선택
df_ins2.loc[101:103]
# loc에는 인덱스에 순서적인 위치개념이 없음, start와 end값을 포함한 그 사이의 모든 값
# 101~103행을 가지는 'smoker'열 값 선택
df_ins2.loc[101:103, 'smoker']
# 변수이름 리스트 활용가능
## 101~103행을 가지는 'smoker', 'region' 열 값 선택 == DataFrame
df_ins2.loc[101:103, ['smoker','region']]
# 변수이름으로 슬라이싱 가능 'smoker' ~ 'charges' 선택 가능
df_ins2.loc[101:103, 'smoker':'charges']
# 모든 관측치(행) 선택할 때는 ':'
df_ins2.loc[:, 'smoker':'charges']
iloc을 활용한 부분 선택
`iloc`은 이름과 상관없이 정수로 표현한 위치, 번호를 활용하며 리스트나 슬라이스 활용 방법은 `loc`와 동일하다.
# 첫번째부터 네번째(0포함 4이전까지) 관측치, 첫번째부터 두번째(0포함, 2이전까지) 속성
df_ins2.iloc[0:4, 0:2]
마무리
데이터를 시각화 하기 전, 데이터 전처리과정이 정말 중요하다고 느꼈다. 활용하고자 하는 데이터프레임을 가지고 어떤 방향으로, 어떤 분석을 해나갈 것인지 뚜렷한 목표를 설정하고, 앞으로 다양한 데이터들을 접해보면서 분석할 수있는 시야를 넓혀가야겠다.
'ABC부트캠프 테크노트' 카테고리의 다른 글
[9일차] ABC부트캠프 : 파이썬 프로그래밍 데이터 집계 및 처리 심화 (0) | 2024.07.16 |
---|---|
[8일차] ABC부트캠프 : 파이썬 프로그래밍 데이터 전처리 & 시각화 (2) | 2024.07.16 |
[6일차] ABC부트캠프 : 파이썬 프로그래밍 미니프로젝트 (0) | 2024.07.11 |
[5일차] ABC부트캠프 : 파이썬프로그래밍 기초3 (0) | 2024.07.10 |
[4일차] ABC부트캠프 : 파이썬 프로그래밍 기초2 (0) | 2024.07.09 |