파이썬-pandas-데이터-프레임-판다1
데이터를 구해보자. 얍!

지난 시간에는 파이썬 pandas Series 사용법을 알아보았습니다. Python pandas에서 시리즈(Series)가 1차원 자료 구조라면 데이터 프레임(DataFrame)은 2차원 자료 구조입니다. 2차원이라는 뜻은 자료 구조가 표 같은 스프레드시트 형식처럼 행과 열로 되어있다는 의미입니다.

pandas(판다스)의 DataFrame의 여러 열에는 서로 다른 종류의 값(숫자, 문자열, 불리언 등)을 담을 수 있습니다. 그리고 행 색인(row indices)과 열 색인(column indices)에 각각 행 이름과 열 이름을 붙일 수도 있죠. 이번 시간에는 데이터를 준비하는 1단계를 알아보겠습니다. 바로 DataFrame을 만들고, DataFrame을 만들기 위해 데이터를 로딩하며, 색인(index)을 관리하는 일입니다. 그럼 Python pandas 사용법, 함께 익혀볼까요?

생성하기(creating)

Python pandas로 DataFrame을 만들려면 어떤 입력 데이터를 사용해야 할까요? DataFrame을 만드는 방법은 크게 사전(dictionary)을 이용하는 법과 리스트(list)/배열(array)을 이용하는 법으로 나뉩니다. 그리고 사전과 리스트/배열 형식의 입력 데이터는 아래와 같이 세부적으로 나뉩니다.

  1. 사전

    • 배열, 튜플, 리스트를 값으로 가지는 사전
    • 사전의 사전
    • Series 객체를 담고 있는 사전
  2. 리스트/배열

    • Numpy 2차원 배열(ndarray)
    • 리스트의 리스트

각 입력 데이터를 이용해 DataFrame을 만드는 법을 차례로 알아보겠습니다. 먼저 사전을 이용해보겠습니다.

사전형 자료 구조는 DataFrame을 만들 때 가장 많이 쓰는 자료 구조입니다. 사전형 자료 구조는 1) 배열, 튜플, 리스트를 값으로 가지는 사전, 2) 사전의 사전, 3) Series 객체를 담고 있는 사전으로 나누어집니다.

1) 배열, 튜플, 리스트를 값으로 가지는 사전

배열, 튜플, 리스트를 값으로 가지는 사전(dictionary of arrays, tuples, lists)이란 사전형 자료 구조에서 각 키에 맵핑(mapping)된 값이 각각 배열, 튜플, 리스트인 자료 구조를 뜻합니다. 이 중에서도 가장 많이 쓰이는 자료형은 리스트를 값으로 가지는 사전입니다. 코드를 통해 알아보겠습니다. 다음 코드는 리스트를 값으로 가지는 사전을 생성하는 예제입니다.

python
data = {
'포켓몬명': ['피카츄', '파이리', '꼬부기', '이상해씨', '버터플', '야도란', '또가스', '잠만보', '뮤','디그다'],
'과': ['이과', '문과', '이과', '이과', '문과', '예체능', '문과', '문과', '문과', '이과'],
'국어': [37, 64, 57, 84, 41, 32, 95, 12, 36, 64],
'수학': [50, 62, 31, 86, 83, 56, 37, 6, 93, 6],
'영어': [60, 93, 1, 82, 2, 6, 98, 21, 7, 60],
'사회': [64, 45, 14, 38, 72, 42, 76, 61, 32, 22],
'과학': [53, 17, 25, 56, 62, 81, 97, 66, 78, 25],
'희망전공': ['전기공학', '미학', '해양생물학', '생물학', '문학', '명상학', '화학', '수면공학', 'NaN', '지질학']
}

위 코드를 실행하면 data라는 변수에 keyvalue가 리스트인 자료 구조가 할당됩니다. 각 과목의 성적 점수는 random 모듈의 randint 메서드(methods)로 만든 결과입니다. randint 함수는 특정 범위 내에 있는 임의의 정수를 반환하는 함수입니다. 이 코드에서와 같이 0점부터 100점 사이에 있는 임의의 정수를 택해 총 10명 학생의 점수를 리스트로 만들려면 다음 코드를 사용하면 됩니다.

python
import random
subject_name = [random.randint(0, 100) for i in range(0, 10)] # 리스트 컴프리헨션

이 사전 객체에서 키에 할당된 값을 가져오려면 data 변수에 대괄호([])를 이용하면 됩니다. 만약, 키가 '포켓몬명'에 해당하는 값을 가져오려면 다음과 같은 코드를 실행하면 됩니다.

python
data['포켓몬명']
# 결과
['피카츄', '파이리', '꼬부기', '이상해씨', '버터플', '야도란', '또가스', '잠만보', '뮤', '디그다']

이제 만든 사전 객체를 DataFrame으로 만들어보겠습니다. DataFrame을 만들 때는 각각 행 색인과 특정 열을 지정할 수 있습니다. 각 경우를 하나씩 살펴보도록 하죠.

행 색인 지정 없이 DataFrame 만들기

첫 번째 방법은 행 색인을 지정하지 않고 DataFrame을 생성하는 것입니다. 이 방법은 DataFrame을 만드는 가장 기본적인 방법입니다. 코드는 다음과 같습니다.

python
df = pd.DataFrame(data)

위 코드에서는 DataFrame 클래스의 매개변수로 사전형 자료 구조를 담고 있는 변수 data를 전달했습니다. 이 코드를 실행하면 다음과 같은 DataFrame이 만들어집니다.

파이썬-pandas-사용법-데이터-프레임-생성-사전형-자료구조-행색인-지정없음
행 색인을 지정하지 않고 만든 DataFrame | Snug Archive

이 DataFrame에서는 기본 정수(ingeter) 색인을 사용합니다. 행 색인을 따로 지정하지 않았기 때문입니다. 가장 왼쪽의 정수 열이 이 DataFrame의 기본 행 색인입니다. 색인을 따로 지정하지 않으면 정수 색인을 사용하는 것이 기본입니다. 이번에는 행 색인을 지정해서 DataFrame을 만들어보도록 하겠습니다.

행 색인 지정해서 DataFrame 만들기

색인을 지정하면 데이터 구조에 접근하고 데이터를 조작하는 것이 쉬워집니다. 행 색인을 지정하려면 DataFrame 클래스에 index 매개변수를 사용하면 됩니다. 다음은 1 이상 10 이하의 구간에 있는 10개 정수에 각각 한글 '번'을 합친 값의 리스트를 행 색인으로 지정해서 DataFrame을 만드는 예제입니다.

python
df = pd.DataFrame(data, index=[f"{i}번" for i in range(1, 11)])

이 코드를 실행하면 다음과 같은 결과가 출력됩니다.

파이썬-pandas-사용법-데이터-프레임-생성-사전형-자료구조-행색인-지정
행 색인을 지정해서 만든 DataFrame | Snug Archive

위 그림을 보면 맨 왼쪽에 초록색으로 표시된 부분이 새로 만들어진 것을 알 수 있습니다. 이 열이 바로 이 DataFrame의 행 색인입니다.

지금까지는 행 색인을 지정하지 않거나 지정해서 DataFrame을 만들어보았습니다. 이번에는 특정 열을 선택해서 DataFrame을 만들어보겠습니다.

특정 열 선택해서 DataFrame 만들기

특정 열을 선택해서 DataFrame을 만들고 싶다면 columns 매개변수를 사용하면 됩니다. 특정 열 3개를 원하는 순서대로 정해서 DataFrame을 만들어보죠. 코드는 다음과 같습니다.

python
df = pd.DataFrame(data, columns=['포켓몬명', '희망전공', '과']) # '포켓몬명', '희망전공', '과' 열 선택

이 코드를 입력하면 아래와 같이 선택한 세 개의 열로 이루어진 DataFrame이 만들어집니다.

파이썬-pandas-사용법-데이터-프레임-생성-사전형-자료구조-특정열-선택
특정 열을 선택해서 만든 DataFrame | Snug Archive

이 DataFrame에서도 행 색인을 지정하지 않았던 첫 번째 예제에서와 같이 기본 정수 색인을 사용합니다. 행 색인을 따로 지정하지 않았기 때문입니다. 만약 행 색인과 특정 열을 모두 지정해서 DataFrame을 만들고 싶다면 indexcolumns 매개변수를 모두 이용하면 됩니다.

행 색인을 지정하고 특정 열을 선택해서 DataFrame 만들기

행 색인과 특정 열을 선택해서 DataFrame을 만드는 방법과 코드는 다음과 같습니다.

  • 색인으로 삼으려는 리스트를 index 매개변수에 전달
  • 특정 열의 이름으로 구성된 리스트를 columns 매개변수에 전달
python
df = pd.DataFrame(data,
index=[f"{i}번" for i in range(1, 11)], # 행 색인 지정
columns=['포켓몬명', '희망전공', '과']) # 특정 열 지정

이 코드를 실행하면 아래와 같은 DataFrame이 만들어집니다.

파이썬-pandas-사용법-데이터-프레임-생성-사전형-자료구조-행색인-특정열-선택
행 색인과 특정 열을 지정해서 만든 DataFrame | Snug Archive

우리가 지정한 3개의 특정 열 순서대로 행 색인이 있는 DataFrame이 만들어졌습니다. 가장 왼편에 있는 열이 행 색인입니다.

만약 사전에 없는 값을 넘기면 해당 키에 맵핑된 값은 결측치 NaN가 됩니다. 다음 코드는 기존 사전에 없던 값을 열로 추가해 DataFrame을 만드는 예제입니다.

python
df = pd.DataFrame(data,
index=[f"{i}번" for i in range(1, 11)],
columns=['포켓몬명', '희망전공', '나이', '직업']) # new: 나이, 직업

이 코드를 실행하면 기존 사전에 없던 키인 '나이'와 '직업'의 모든 값이 NaN으로 처리됩니다. 만들어진 DataFrame을 확인해보시죠.

파이썬-pandas-사용법-데이터-프레임-생성-사전형-자료구조-키없음-NaN처리
사전에 없는 키를 사용하면 결측치 NaN으로 처리되는 DataFrame | Snug Archive

지금까지 리스트를 값으로 가지는 사전으로 DataFrame을 만드는 네 가지 방법을 알아보았습니다. 사전형 자료 구조를 이용해 DataFrame을 만드는 두 번째 방법은 사전의 사전을 이용하는 것입니다.

2) 사전의 사전

사전의 사전(nested dictionary)이란 사전 안에 사전이 있는 사전입니다. 말 그대로 사전이 사전 안에 중첩된 자료 구조를 뜻하죠. 중첩된 사전을 DataFrame을 만드는 입력 데이터로 사용할 때는 바깥에 있는 사전의 키가 열 색인이 되고 안에 있는 키는 행 색인이 됩니다. 아래 코드와 코드를 실행한 결과를 보면, 안쪽에 있던 키가 행 색인이 되고 바깥쪽에 있던 키가 열 색인이 된 것을 알 수 있습니다.

python
data2 = {'수면시간': {'1번': 5, '2번': 3, '3번': 6},
'능력치': {'1번': 8, '2번': 4, '3번': 5}}
df2 = pd.DataFrame(data2)
# 결과
수면시간 능력치
15 8
23 4
36 5

행 색인을 다른 값으로 변경할 수도 있습니다. 이 경우에는 기존의 색인에 매핑된 값은 그대로 유지되고 새로운 색인에 해당하는 값은 NaN이 됩니다. 실행 코드와 결과는 아래와 같습니다.

python
pd.DataFrame(data2, index=['0번', '1번', '2번']) # 행 색인 지정
# 결과
수면시간 능력치
0번 NaN NaN
15.0 8.0
23.0 4.0

이 DataFrame에는 행 색인이 새로 지정된 것을 확인할 수 있습니다. 그리고 새로운 색인에 해당하는 값은 NaN 처리가 되었죠.

사전형 자료 구조로 DataFrame을 만드는 마지막 방법은 Series 객체를 담고 있는 사전을 이용하는 것입니다.

3) Series 객체를 담고 있는 사전

Series를 값으로 가지는 사전이란 사전의 키에 해당하는 값이 Series인 경우를 말합니다. Series 객체를 담고 있는 사전을 이용해서 DataFrame을 만들 때도 사전의 사전으로 DataFrame을 만들 때와 동일한 방식으로 DataFrame을 생성합니다. 다음 코드는 위에서 만든 DataFrame에서 행을 슬라이싱(slicing) 해온 Series 객체를 이용해 DataFrame을 만드는 예제입니다. 슬라이싱은 아래 데이터 선택에서 자세히 다루겠습니다.

python
data3 = {'수면시간': df2['수면시간'][:-1], # 처음부터 마지막 행 전까지
'능력치': df2['능력치'][:2]} # 처음부터 1행까지
pd.DataFrame(data3)
# 결과
수면시간 능력치
15 8
23 4

지금까지 3가지 종류의 사전형 자료 구조로 DataFrame을 만드는 법을 알아보았습니다. 이번에는 리스트/배열로 DataFrame을 만드는 법을 알아보겠습니다.

4) 리스트의 리스트

리스트의 리스트(list of lists)는 리스트 안에 리스트가 있는 자료 구조를 말합니다. 리스트의 리스트로 DataFrame을 만들 때도 사전형 구조에서와 마찬가지로 행 색인과 열을 정할 수 있습니다. 여기서는 columns를 이용해 열 이름만 지정해서 DataFrame을 만드는 법을 알아보겠습니다. 행 색인을 지정하고 싶다면 index를 사용하면 됩니다.

다음 코드는 '과일명'과 '수량'이라는 이름으로 열 이름을 지정해서 리스트의 리스트로 DataFrame을 만드는 예제입니다.

python
data4 = [['사과', 2], ['딸기', 5], ['수박', 1]]
df4 = pd.DataFrame(data4, columns=['과일명', '수량']) # 열 이름 지정
# 결과
과일명 수량
0 사과 2
1 딸기 5
2 수박 1

열의 이름이 각각 '과일명'과 '수량'인 DataFrame이 만들어졌습니다. 이번에는 Numpy의 2차원 배열로 DataFrame을 만들어보겠습니다.

5) Numpy 2차원 배열(ndarray)

Numpy로 배열을 만들려면 행으로 만들 리스트를 array 함수에 전달하면 됩니다. 여기서 Numpy는 import numpy as np 코드를 사용해 np로 임포트되었다고 가정합니다. 코드는 다음과 같습니다.

python
array = np.array([[100, 50, 70, 90], [10, 20, 30, 40]])
df5 = pd.DataFrame(array)
# 결과
0 1 2 3
0 100 50 70 90
1 10 20 30 40

행 색인과 특정 열을 선택해서 DataFrame을 만들 수도 있습니다. 다음 코드는 Numpy의 arange 함수를 이용해 배열을 만들고 reshape 함수로 행과 열을 재배열한 다음 행 색인과 열 이름을 지정해 DataFrame을 만드는 예제입니다.

python
df6 = pd.DataFrame(np.arange(8).reshape((2, 4)),
index=['사과', '감자'],
columns=['밭1', '밭2', '밭3', '밭4'])
# 결과
1234
사과 0 1 2 3
감자 4 5 6 7

지금까지 사전 자료형과 리스트/배열을 사용해 DataFrame을 만드는 방법을 살펴보았습니다. 만약 입력 데이터를 직접 만들지 않는다면 다른 곳에서 가져오면 됩니다. 이를 데이터 로딩(loading)이라고 합니다. 이번에는 데이터를 불러오는 법을 알아보겠습니다.

로딩하기(loading), 저장하기(saving)

Python pandas에서 데이터를 로딩하려면 텍스트 파일, 웹 API, 데이터베이스를 이용하는 방법이 있습니다. 여기서는 가장 자주 쓰는 텍스트 파일(CSV 파일, 엑셀 파일, .txt 파일)을 가져오는 법을 알아보겠습니다. 웹 API에서 데이터를 가져오고 싶은 분들은 파이썬 웹 스크래핑 실습하기을 참조하시면 됩니다.

1) CSV 파일 읽기, 저장하기: read_csv, to_csv

CSV(Comma-Separated Values)는 쉼표(,)를 구분자(separator)로 하는 텍스트 파일입니다. pandas에서 CSV 파일을 읽어오고 싶을 때는 read_csv함수를 사용하면 됩니다. 다음 코드는 CSV 파일을 가져와 DataFrame으로 만드는 예제입니다.

python
df = pd.read_csv('data.csv')

만약 CSV 파일로 저장하고 싶다면 아래와 같이 to_csv 함수를 사용하면 됩니다. 특히, 한글 CSV 파일을 저장할 때 encoding='utf-8-csv' 옵션을 함께 주면 한글 깨짐 현상을 막을 수 있습니다.

python
pd.to_csv('data.csv', encoding='utf-8-sig') # 'utf-8-sig'는 한글 파일 깨짐을 방지함

read_csv 함수 인자에는 50개 이상의 옵션이 있습니다. 역시 to_csv 함수 인자에도 20개 이상의 옵션이 있습니다. 각 함수의 모든 옵션은 pandas 공식 홈페이지 pandas.read_csvpandas 공식 홈페이지 pandas.to_csv에서 확인하실 수 있습니다. 여기서는 read_csv 함수 중에서 자주 쓰이는 옵션만 살펴보겠습니다. 각 옵션을 실행해보시고 어떤 결과가 나오는지 확인해보세요.

헤더 설정하기: header

header는 헤더로 가져올 행을 지정하는 옵션입니다. header의 값은 헤더로 사용할 열들의 이름이 있는 위치를 나타냅니다. 예를 들어, 가져올 데이터에서 컬럼명이 있는 행이 두 번째 행에 있다면 header=1을 사용하면 됩니다. 만약 데이터에 열 이름이 없다면(데이터 레코드로 바로 시작한다면) 옵션에 None을 전달하면 됩니다. 코드는 다음과 같습니다.

python
df = pd.read_csv('data.csv', header=0) # 가져올 데이터에서 컬럼명이 있는 행이 0번째 행
df = pd.read_csv('data.csv', header=None) # 헤더 지정 안하고 데이터 가져오기

만약 첫 번째 행과 두 번째 행을 계층적 색인(hierarchical index)으로 지정하고 싶다면 아래와 같이 header[0, 1]과 같은 리스트를 전달하면 됩니다.

python
df = pd.read_csv('data.csv', header=[0, 1])

계층적 색인은 아래 '색인 관리'에서 자세히 알아보겠습니다.

열 이름 설정하기: names

names 옵션은 열의 이름을 지정합니다. 만약 각 열에 순서대로 '가', '나', '다', '라'라는 이름을 붙이고 싶다면 아래와 같이 names 옵션에 이 값을 담은 리스트를 할당하면 됩니다.

python
df = pd.read_csv('data.csv', names=['가', '나', '다', '라']) # 열 이름 붙이기

선택한 열을 행 색인으로 지정하고 통합 색인명 부여하기: index_col

index_col 옵션은 선택한 열을 행 색인으로 지정하면서 통합 행 색인명 만들어줍니다. 다음 코드는 '포켓몬정보'라는 이름의 열을 행 색인으로 지정하고 지정한 행 색인의 통합 색인명을 '포켓몬정보'라고 붙이는 예제입니다.

python
df = pd.read_csv('data.csv', index_col='포켓몬정보')

만약 계층적 색인을 지정하고 싶다면 열 번호나 열 이름의 리스트를 옵션에 넘기면 됩니다. 다음 코드는 '포켓몬명'과 '과'라는 이름을 지는 열 2개를 계층적 색인으로 만드는 예제입니다.

python
df = pd.read_csv('data.csv',
index_col=['포켓몬명', '과'])

데이터 시작부터 행 건너뛰기: skiprows

skiprows 옵션은 파일의 시작부터 무시할 행의 개수를 지정합니다. 예를 들어 skiprows=1은 1개 행을 건너뛰고 2번째 행부터 데이터를 가져오겠다는 의미입니다(지정된 개수만큼 건너뜀).

python
df = pd.read_csv('data.csv', skiprows=2) # 2개 행 건너뛰고 3번째 행부터 가져오기

skiprows 옵션은 데이터의 열이름이 담긴 행이 첫 번째 행에 위치하지 않을 때 사용하면 됩니다. 예를 들어, 열 이름이 담긴 위치가 2번째 행이라면 skiprows=1을 옵션으로 주면 되겠죠.

만약 skiprows 옵션에서 데이터의 첫 부분부터 시작해 특정 행을 건너뛰고 싶다면 아래와 같이 이 옵션에 건너뛰고 싶은 정수 색인값을 담은 리스트를 할당하면 됩니다.

python
df = pd.read_csv('data.csv', skiprows=[0, 2, 4]) # 0행, 2행, 4행 빼고 데이터 가져오기

데이터 끝부터 행 건너뛰기: skipfooter

skipfooterskiprows와는 반대로 데이터의 끝 부분부터 시작해 몇 개 행을 생략하고 데이터를 불러올 것인지를 정합니다.

python
df = pd.read_csv('data.csv', skipfooter=2) # 마지막 행을 포함해서 2개 행 건너뛰고 데이터 가져옴

첫 몇 줄만 읽어오기: nrows

nrows 옵션은 파일의 첫 부분만 읽어오고 싶을 때 사용합니다. 이 옵션은 처음부터 몇 줄까지 읽어올 것인지를 지정합니다.

python
df = pd.read_csv('data.csv', nrows=3) # 데이터의 시작부터 총 3개 행 가져오기

다음과 같이 skiprowsnrows을 함께 쓸 수도 있습니다.

python
df = pd.read_csv('data.csv',
skiprows=2 # 처음 2개 행 무시하기
nrows=5) # 그 이후부터 5개 행 가져오기

불러오고 싶은 열 지정하기: usecols

usecols 옵션은 데이터에서 가져오고 싶은 열을 지정하는 옵션입니다. 예제 코드는 다음과 같습니다.

python
df = pd.read_csv('data.csv', usecols=[0, 1]) # 0번째, 1번째 열만 로딩하기
df = pd.read_csv('data.csv', usecols=['포켓몬명', '희망전공']) # 이 2개 열만 로딩하기

특정 열 1개를 제외하고 데이터를 가져오려면 lambda 함수를 사용하면 됩니다. 예시 코드는 다음과 같습니다.

python
df = pd.read_csv('data.csv', usecols=lambda x: x !='포켓몬명') # '포켓몬명' 열 제외

만약, 다수의 특정 열을 제외하고 데이터를 가져오고 싶다면 다음과 같은 코드를 사용하면 됩니다.

python
columns_to_skip = ['국어', '수학']
df = pd.read_csv('data.csv', usecols=lambda x: x not in columns_to_skip)

결측치 처리하기: na_values

na_values 옵션은 결측치를 어떻게 표기할 것인지 정할 때 사용합니다. 예를 들어, 다음 코드에서와 같이 na_values=['없음'] 을 사용하면 결측치가 NaN 대신 '없음'으로 표시됩니다.

python
df = pd.read_csv('data.csv', na_values=['없음'])

인코딩 설정하기: encoding

encoding 옵션은 유니코드(Unicode) 인코딩 종류를 지정합니다. 한글의 경우 utf-8-sig를 지정하면 한글 깨짐 현상 없이 파일을 잘 불러올 수 있습니다.

python
df = pd.read_csv('data.csv', encoding='utf-8-sig')

지금까지 CSV 파일을 읽는 법을 살펴보았습니다. 다음은 엑셀 파일을 로딩하는 법을 알아보겠습니다.

2) 엑셀 파일(.xlsx) 읽기, 저장하기: read_excel / to_excel

파이썬 pandas에서 엑셀 파일을 가져올 때는 read_excel 함수를 사용합니다. 기본 코드는 다음과 같습니다.

python
df = pd.read_excel('data.xlsx')

엑셀 파일을 로딩할 때는 위에서 CSV 파일 로딩을 할 때 사용한 옵션 중 encoding을 제외하고 모두 사용할 수 있습니다. 특히 usecols 옵션에 슬라이싱을 사용하면 특정 구간의 데이터만 불러올 수 있습니다. usecols의 슬라이싱 기능은 CSV 파일에서는 작동하지 않습니다. 코드는 다음과 같습니다.

python
df = pd.read_excel('data.xlsx', usecols='B:D') # B 컬럼부터 D 컬럼까지 가져오기

데이터를 엑셀 파일로 저장하고 싶다면 아래와 같이 to_excel 함수를 사용하면 됩니다.

python
pd.to_excel('data.xlsx')

지금까지 엑셀 파일을 로딩해서 DataFrame을 만드는 법을 알아보았습니다. 마지막으로 .txt 파일을 불러와 DataFrame을 만드는 법을 알아보겠습니다.

3) .txt 파일 읽기: read_csv(sep=' ' or '\t')

파일 확장자가 .txt인 파일을 불러올 때는 엑셀 파일을 로딩할 때와 마찬가지로 read_csv 함수를 사용하되, sep 옵션으로 구분자를 지정하면 됩니다. 예제 코드는 다음과 같습니다.

python
df = pd.read_csv('data.txt', sep='\t') # 구분자 tab 사용

.txt 파일은 구분자가 없기 때문에 " " 또는 "\t" 등의 구분자를 넣어주어야 합니다. 옵션으로는 sep 대신 delimiter를 사용해도 됩니다.

지금까지 데이터를 생성하고 읽어오는 방법을 알아보았습니다. 이번에는 데이터의 색인을 관리하는 법을 알아보겠습니다.

색인 관리하기(index managing)

색인 객체(index objects)란 표 형식의 데이터에서 각 행과 열에 대한 메타데이터를 저장하는 객체입니다. 이 인덱스(Index) 객체는 배열과 유사하게 고정 크기로 동작합니다. 고정 크기로 동작한다는 의미는 각 값에 할당된 메모리의 크기가 일정하게 유지된다는 뜻입니다.

또한, 일단 색인으로 지정하면 색인의 내용을 변경할 수 없습니다. 한 번 지정하면 색인의 내용을 변경할 수 없다는 점은 색인이 자료 구조 사이에서 안전하게 공유되는 장점을 지닙니다. 그래서 색인을 지정하면 데이터 사이에서 혼동되지 않고 더 정확하고 효율적으로 데이터를 분석할 수 있게 됩니다.

파이썬 pandas의 색인은 단층 색인과 다중 색인으로 나뉩니다. 일반 색인은 계층이 1차원인 색인입니다. 다중 색인은 축에 여러 색인 단계(level)가 있는 색인을 의미합니다. 그래서 계층적 색인, 멀티인덱스(MultiIndex)라고도 불리죠. 그럼 색인을 관리하는 도구를 알아보도록 하겠습니다.

1) 생성: Index

색인을 리스트 형태로 DataFrame 클래스에 전달하지 않고 Index 클래스로 직접 만들 수도 있습니다. 다음 코드는 Index 클래스를 사용해 라벨을 만든 다음 이 라벨을 DataFrame의 인자로 사용하는 예시입니다.

python
labels = pd.Index(['eunhee네', 'hansoo네']) # 정수 행 색인 생성
labels # Int64Index([0, 1, 2, 3], dtype='int64')
df7 = pd.DataFrame(np.arange(8).reshape((2, 4)),
index=labels,
columns=['전체', '밭1', '밭2', '밭3'])
# 결과
전체 밭123
eunhee네 0 1 2 3
hansoo네 4 5 6 7

2) 확인: index, columns

색인명을 확인하려면 indexcolumns 속성을 이용하면 됩니다. 먼저 행 색인의 이름을 알아보겠습니다.

행 색인: index

행 색인명을 알고 싶다면 index 속성을 사용하면 됩니다. 기본 코드는 아래와 같습니다.

python
df.index
# 결과
Index(['1번', '2번', '3번', '4번', '5번', '6번', '7번', '8번', '9번', '10번'], dtype='object')

만약 행 색인에 특정 색인이 있는지 확인하려면 다음 코드를 사용하면 됩니다.

python
'포켓몬명' in df.index
# 결과
False

열 색인도 확인해보겠습니다.

열 색인: columns

열 색인을 확인하고 싶다면 columns 속성을 이용하면 됩니다. 기본 코드는 다음과 같습니다.

python
df.columns
# 결과
Index(['포켓몬명', '과', '국어', '수학', '영어', '사회', '과학', '희망전공'], dtype='object')

특정 열이 열 색인에 있는지 확인하려면 다음 코드를 사용하시면 됩니다.

python
'과' in df.columns
# 결과
True

파이썬의 집합과는 달리 pandas의 인덱스는 중복되는 값을 허용합니다. 중복되는 색인값을 사용하면 해당 값을 가진 모든 항목이 선택됩니다.

python
dup_labels = pd.Index(['감자', '감자', '고구마', '미나리'])
# 결과
Index(['감자', '감자', '고구마', '미나리'], dtype='object')

만약 중복되는 색인이 있는지 확인하고 싶다면 is_unique 속성을 사용하면 됩니다. is_unique 속성은 행 색인의 값이 유일한지 아닌지를 알려줍니다.

python
df.index.is_unique # 행 색인 중복 확인
df.columns.is_unique # 열 색인 중복 확인
# 결과
True # 동일한 이름의 행 색인 없음
True # 동일한 이름의 열 색인 없음

중복되는 색인값이 없으면 해당 색인에 대한 스칼라값이 반환됩니다. 만약 중복되는 색인값이 있으면 각 색인에 해당하는 값이 모두 반환됩니다.

3) 지정: set_index

특정 열을 행 색인으로 설정하려면 set_index 함수를 사용하면 됩니다.

python
df5.set_index('전체') # '전체'라는 이름을 지닌 열을 행 색인으로 지정하기
# 결과
123
전체
0 1 2 3
4 5 6 7

set_index 함수를 사용해서 얻은 DataFrame은 내부 데이터에 대한 뷰(view) 입니다. 뷰라는 의미는 복사본이 아니라는 뜻입니다. 따라서 원래 DataFrame을 출력해보면 변화가 없습니다. 만약 행 색인으로 지정한 열을 DataFrame에 반영하고 싶다면 아래와 같이 inplace 옵션으로 True 값을 전달하면 됩니다.

python
df5.set_index('전체', inplace=True)

만약 계층적 행 색인을 지정하고 싶다면 set_index에 리스트를 인자로 전달하면 됩니다.

python
df5.set_index(['밭1', '밭2'])

계층적 색인으로 만든 열을 열로도 남겨두려면 다음과 같이 drop=False 옵션을 추가하면 됩니다.

python
df5.set_index(['밭1', '밭2', drop=False]) # 계층적 색인 지정 & 열로도 남기기

4) 정렬: sort_index

색인을 정렬하려면 sort_index 함수를 사용하면 됩니다. sort_index 함수는 데이터를 오름차순으로 정렬합니다. 아래와 같이 sort_index 함수로는 행 색인을 정렬할 수도 있고, 열 색인을 정렬할 수도 있습니다.

행 색인

기본적으로 sort_index 함수는 오름차순으로 DataFrame을 정렬합니다.

python
df.sort_index()

만약 행 색인을 내림차순으로 정렬하고 싶다면 ascending 옵션에 False 값을 주면 됩니다.

python
df.sort_index(ascending=False)

열 색인도 정렬해보겠습니다.

열 색인

열 색인을 정렬하고 싶다면 sort_index 함수에 옵션으로 axis=1 을 주면 됩니다. 여기서 1은 열을 의미합니다. 행 색인과 마찬가지로 열 색인도 오름차순으로 정렬됩니다. 코드는 다음과 같습니다.

python
df.sort_index(axis=1)

열 색인을 내림차순으로 정렬하고 싶다면 행 색인을 내림차순으로 정렬할 때와 마찬가지로 ascending=False 옵션을 사용하면 됩니다.

python
df.sort_index(axis=1, ascending=False)

만약 계층적 색인이 있는 경우에 sort_index를 사용하려면 level 옵션을 사용할 수 있습니다. level 옵션은 어느 계층을 기준으로 정렬할 것인지를 지정할 수 있습니다. 예제 코드는 아래와 같습니다.

python
df.sort_index(level=1) # 차상위 계층 정렬

5) 색인명 부여: index.name, columns.name

색인명을 지정하는 방법에는 index.name 속성과 columns.name을 이용하는 법이 있습니다. index.name 행 색인을 지정합니다. columns.name은 열 색인을 지정합니다.

행 색인명 지정: index.name

행 색인명을 지정하려면 index.name 속성을 사용하면 됩니다. 다음 코드는 행 색인명으로 '반번호'를 지정합니다.

python
df.index.name = '반번호'
# 결과
Index(['1번', '2번', '3번', '4번', '5번', '6번', '7번', '8번', '9번', '10번'],
dtype='object',
name='반번호') # 행 색인명 지정

index.name을 사용하면 행 색인명이 DataFrame에 바로 반영됩니다.

열 색인명 지정: columns.name

열 색인명을 지정하려면 columns.name 속성을 사용하면 됩니다. 기본 코드는 다음과 같습니다.

python
df.columns.name = '포켓몬정보'
# 결과
Index(['포켓몬명', '과', '국어', '수학', '영어', '사회', '과학', '희망전공'],
dtype='object',
name='포켓몬정보') # 열 색인명 지정

columns.name 속성 역시 index.name과 마찬가지로 지정한 열 색인명이 DataFrame에 바로 반영됩니다.

6) 색인명 변경: index.names, columns.names

행 색인명을 변경하고 싶은 경우에는 index.names 속성을 사용하면 됩니다. 반대로, 열 색인명을 변경하고 싶을 때는 columns.names을 사용하면 됩니다.

index.names

python
df.index.names = ['반'] # 기존 색인명이 '반'으로 변경됨

계층적 색인명을 변경하고 싶을 경우에는 리스트 값을 전달하면 됩니다. 예를 들어 계층적 색인이 '포켓몬명'과 '도감번호'인 DataFrame에서 색인명을 변경하고 싶다면 다음 코드를 사용할 수 있습니다.

python
df.index.names = ['반', '번호'] # '포켓몬명'을 '반'으로 '도감번호'를 '번호'로 변경하기

columns.names

열 색인명을 변경하고 싶을 때는 columns.names 속성을 사용하면 됩니다.

python
df.columns.names = ['식별코드'] # 열 색인이 1개일 때 해당 열 색인 이름을 '식별코드'로 변경

만약 계층적 색인일 경우에는 아래와 같이 리스트를 사용하면 됩니다.

python
df.columns.names = ['ID', '번호']

7) 계층 변경: swaplevel

swaplevel 함수는 다중 계층에서 계층의 순서를 바꾸고 정렬합니다. 만약 key1key2의 계층을 서로 바꾸고 싶다면 다음 코드를 사용하면 됩니다.

python
df.swaplevel('key1', 'key2') # 'key1'과 'key2'의 계층 변경, swaplevel(0, 1)과 동일

만약 계층 순서를 서로 바꾼 뒤 최상위 계층을 기준으로 데이터를 정렬하고 싶다면 다음 코드를 사용할 수 있습니다.

python
df.swaplevel(0, 1).sort_index(level=0) # 계층 순서 바꾼 뒤 최상위 계층 정렬

8) 재색인: reindex, rename, index.map

재색인(reindexing)은 새로운 색인에 맞도록 객체를 새로 생성하는 작업을 의미합니다. 재색인을 하는 방법에는 reindex 속성, rename 함수, index.map을 이용하는 법이 있습니다.

reindex

reindex를 호출하면 데이터를 새로운 색인에 맞게 재배열합니다. 존재하지 않는 색인값이 있다면 NaN을 추가하죠. 예제를 통해 알아보겠습니다.

행 재색인

먼저 행을 재색인해보겠습니다. 예제 코드는 다음과 같습니다.

python
df4.reindex([1, '은희네']) # 행 재색인
# 결과
전체 밭123
1 4.0 5.0 6.0 7.0
은희네 NaN NaN NaN NaN

시계열 같은 순차적인 데이터를 재색인할 때는 값을 보간하거나 채워 넣어야 할 경우가 있습니다. 이때는 method 옵션을 이용해 누락된 값을 채워 넣을 수 있습니다.

python
object = pd.Series(['개', '고양이', '토끼'], index=[0, 2, 4])
# 결과
0
2 고양이
4 토끼
dtype: object
object.reindex(range(6), method='ffill') # 누락된 값을 직전의 값으로 채워 넣기
# 결과
0
1
2 고양이
3 고양이
4 토끼
5 토끼
dtype: object
열 재색인

다음은 열을 재색인하는 코드입니다.

python
columns = ['밭1', '논1', '밭2', '밭4']
df4.reindex(columns=columns) # 열 재색인
# 결과
1124
0 1 NaN 2 NaN
1 5 NaN 6 NaN

'밭1'과 '밭2' 색인은 기존에 있었기 때문에 값을 불러왔습니다. 새로 추가된 색인 '논1'과 '밭4'는 불러올 값이 없어 NaN으로 표시된 것을 알 수 있습니다.

rename

원래 객체를 변경하지 않고 새로운 객체를 생성해서 색인으로 지정한 열 값을 바꾸고 싶다면 rename 메서드를 사용하면 됩니다. 이 메서드를 사용하면 DataFrame을 직접 복사해서 행 색인과 열 색인 속성을 갱신할 필요 없이 DataFrame을 바로 변경할 수 있습니다.

python
df5.rename(index=str.title, columns=str.upper)
# 결과
전체 밭123
Eun 0 1 2 3
Han 4 5 6 7

rename 메서드로는 축 이름 중 일부만 변경할 수도 있습니다. 이때는 아래와 같이 사전 형식의 객체를 사용하면 됩니다.

python
df5.rename(index={'eunhee네': '은희네'}, # 'eunhee네'를 '은희네'로 변경
columns={'밭1': '논1'}) # '밭1'을 '논1'로 변경
# 결과
전체 논123
은희네 0 1 2 3
hansoo네 4 5 6 7

원본 데이터를 바로 변경하려면 이 코드에 inplace=True 옵션을 주면 됩니다.

index.map

index.map 함수를 사용하면 행 색인으로 지정한 값 전부를 변경할 수 있습니다. 이 함수를 사용하면 행 색인의 변경된 값이 DataFrame에 바로 반영됩니다.

python
transform = lambda x: x[:3].upper()
df7.index = df7.index.map(transform)
# 결과
Index(['EUN', 'HAN'], dtype='object')

9) 초기화: reset_index

reset_index 함수는 set_index와 반대되는 함수입니다. 이 함수는 색인을 초기화합니다. 계층적 색인을 지정했을 때 다시 열 단위 DataFrame으로 만들어 주는 역할도 합니다.

python
df.reset_index()
df.reset_index(drop=True) # 사용했던 색인을 삭제
df.reset_index(drop=True, inplace=True) # 사용했던 색인을 삭제하고 DataFrame에 반영

지금까지 Python pandas 사용법으로 데이터 프레임을 생성하는 법, 데이터를 로딩하는 법 그리고 색인을 관리하는 법을 알아보았습니다. 다음 시간에는 Python pandas의 DataFrame에서 Python pandas 데이터 확인, 정렬, 선택하는 법을 알아보겠습니다. 모두 수고 많으셨습니다.

참고 문헌

...

©2022 Snug Archive. All rights reserved.

Contact me at snugarchive@gmail.com.