이 포스팅에서는 예제를 통해 데이터프레임 내의 데이터를 가공하는 여러 가지 방법을 소개한다.

(1) rename, drop, loc, append, reindex

  • 인덱스와 컬럼 이름 바꾸기
  • 인덱스와 컬럼 추가, 삭제하기
  • 인덱스와 컬럼 순서 바꾸기

(2) sort_index, sort_values, query, filter, numpy.where, merge

  • 인덱스와 컬럼 내림차순, 오름차순 정렬하기
  • 특정 조건에 맞는 데이터 찾기
  • 특정 조건에 따라 컬럼 값 추가하기
  • 데이터프레임 병합하기


Q.

 의뢰소에서 임무를 받은 풋내기 모험가 '리오'는, 모험을 시작하기 전에 인벤토리(DataFrame)에 다양한 종류(column)의 아이템(index)을 마련하였다.

 모험을 마치고 돌아온 리오의 가방은 다음과 같은 상태였다.

# 공간 정리에 필요한 연장을 챙기자
import numpy
from pandas import DataFrame
from pandas import Series

# 가방의 현재 상태
backpack=[
    {'이름':'나이프','가격':20,'무게':5,'공격력':3,'EA':1},
    {'이름':'포션','가격':5,'무게':1,'EA':5},
    {'이름':'셔츠','가격':30,'무게':4,'방어력':2,'EA':1},
    {'이름':'해독제','가격':8,'무게':1,'EA':0},
    {'이름':'부싯돌','가격':15,'무게':3,'EA':1}]

가방 공간을 보기 좋게 정리하고, 가방에 새로 얻은 간식을 넣고, 가방 속 아이템의 상태를 확인해 보자.

# 가방에 넣을 간식의 데이터
pizza={'이름':'식은 피자 조각','가격':5,'무게':1,'EA':1,'청결':-1}

A.

 가방 속 아이템들은 리스트 공간 내 딕셔너리로 구성되어 있다. 이제 가방을 정리하기 위해, 아이템을 데이터프레임 형태로 바꿔 보기로 하자.

# 데이터프레임으로 만들기
backpack_df=DataFrame(backpack, index=backpack['이름'])

 데이터프레임으로 저장된 가방은 다음과 같은 형태이다.

가방 공간을 보기 좋게 정리하고, 가방에 새로 얻은 간식을 넣고, 가방 속 아이템의 상태를 확인해 보자.


  • 인덱스와 컬럼 이름 바꾸기

데이터프레임 내의 EA는 영어로 된 컬럼이라서, 영어에 약한 리오의 마음에 들지 않았다. 그래서 리오는 EA를 '갯수'로 바꿔 부르기로 마음먹었다.

EA는 '열 이름'이고, 이것을 '컬럼column'이라 부른다. 아이템 이름 왼쪽에 보이는 숫자는 '인덱스 index'라 부른다. 컬럼과 인덱스의 이름은 rename() 기능으로 수정할 수 있다.

컬럼 이름 수정 : .rename( columns= { '기존 컬럼 이름 1' : '바꿀 컬럼 이름 1' , '기존 컬럼 이름 2' : '바꿀 컬럼 이름 2', ... } )

인덱스 이름 수정 : .rename( index={'기존 인덱스 이름 1' : '바꿀 인덱스 이름 1', '기존 인덱스 이름 2' : '바꿀 인덱스 이름 2', ... } )

# 컬럼 이름 바꾸기 : .rename( columns= { '기존컬럼이름' : '바꿀컬럼이름' } )
# 원래의 데이터프레임에 변경사항 덮어씌우기 : inplace=True

backpack_df.rename(columns={'EA':'갯수'}, inplace=True)

 컬럼 이름을 바꾸면 다음과 같이 저장된다.

리오는 가방 구석에 붙어 있는 0~4까지의 번호도 마음에 들지 않으니, 아이템 이름을 번호 대신 넣어 보기로 하였다.

인덱스 이름을 변경하기 위해서는 rename( index= 부분에 들어갈 딕셔너리 자료가 필요하다. { 0 : '나이프', 1 : '포션' ...} 과 같이 직접 입력하는 방법도 있지만, 아이템이 아주 많을 때에도 편하게 정리하기 위해 우선 반복문을 사용해서 인덱스 변경용 딕셔너리를 만들기로 한다.

# 인덱스 변경을 위한 딕셔너리를 반복문 앞에 미리 정의하자
idxchange={}

# enumerate( Series ) 로 두 개의 값을 받아 순서대로 저장
for i,v in enumerate(backpack_df['이름']):
                     idxchange[i]=v

print(idxchange)

idxchange에 원하는 모양이 잘 저장된 것을 확인할 수 있다.

{0: '나이프', 1: '포션', 2: '셔츠', 3: '해독제', 4: '부싯돌'}

이제 이 딕셔너리를 인덱스 변경 코드 안에 넣고, 결과를 확인해 보자.

# 인덱스 변경 : .rename( index = { '변경전' : '변경후' } )

backpack_df.rename(index=idxchange, inplace=True)

 맨 왼쪽 인덱스에 있던 숫자가 아이템 이름으로 바뀐 것을 볼 수 있다.


  • 인덱스와 컬럼 추가, 삭제하기

 인덱스에 아이템 이름이 잘 들어가 있으므로, 자료가 중복되는 '이름' 컬럼은 삭제해도 문제 없게 되었다.

컬럼 삭제는 .drop( ['컬럼1', '컬럼2', ... ], axis=1) 를 이용한다. 인덱스 삭제의 경우 .drop(['인덱스1', '인덱스2', ... ], axis=0)이다.

axis 파라미터의 기본값은 0이며, 인덱스 삭제 시에는 파라미터를 지정하지 않아도 된다.
또한 인덱스 번호, 슬라이싱 숫자를 넣어 컬럼과 인덱스를 일괄삭제할 수도 있다.
예) .drop( [ 0 : 3 ], axis=1 ) 로 0번째부터 2번째까지의 열 삭제

컬럼 삭제 코드를 입력하면,

# 컬럼 삭제 : .drop(['컬럼1','컬럼2'], axis=1)

backpack_df.drop(['이름'],axis=1, inplace=True)

backpack_df 에서 '이름' 열이 삭제된 것을 확인할 수 있다.


 가방 정리를 마친 리오는 조금 배가 고파졌다. 길거리에서 군것질거리를 조금 사 먹고, 남은 간식을 가방에 넣어 두기로 하였다.

 앞서 주어진 간식의 데이터는 다음과 같다.

# 가방에 넣을 간식의 데이터
pizza={'이름':'식은 피자 조각','가격':5,'무게':1,'EA':1,'청결':-1}

 데이터프레임에 새 행을 추가하는 방법은 여러 가지가 있다.


i) 딕셔너리를 .loc 기능을 이용하여 데이터프레임에 추가하기

리스트나 딕셔너리를 데이터프레임에 추가할 경우, 데이터프레임과 추가하려는 아이템의 컬럼 수, 종류가 일치해야만 한다. 딕셔너리의 키('가격', '갯수' 등등) 순서는 달라도 상관없다.

데이터프레임 행 추가 : 데이터프레임.loc['새 컬럼 이름'] = [ 추가하려는 리스트 (또는 딕셔너리) ]

pizza (식은 피자 조각) 데이터는, 현재의 backpack_df 와 컬럼이 일치하지 않는다. 그러므로, 모자란 컬럼(공격력, 방어력)을 추가하고, 일치하지 않는 데이터(EA, 갯수, 이름)의 형태를 수정하거나 삭제해야 한다.

pizza 딕셔너리를, 가방 컬럼에 들어갈 수 있는 형태로 가공해 보자.

# 원래 가방과 똑같은 가방 만들기 .copy()
backpack2_df=backpack_df.copy()

# '이름', '청결' 컬럼 삭제하기
pizza.pop('이름')
pizza.pop('청결')

# 'EA' 컬럼을 뽑아내고 '갯수' 컬럼으로 바꾸기
pizza['갯수']=pizza.pop('EA')

# 모자란 컬럼 두 가지 추가하기
pizza['공격력']=None
pizza['방어력']=None

# 가공된 pizza 딕셔너리 확인하기
print(pizza)

가공 후 출력한 pizza의 데이터는 다음과 같다.

{'가격': 5, '무게': 1, '갯수': 1, '공격력': None, '방어력': None}

이제 식은 피자 조각을 가방에 넣어 보자.

# 딕셔너리 행 추가 : .loc['추가할 컬럼 이름']= {}
backpack2_df.loc['식은 피자 조각']=pizza

이후 backpack2_df 가방의 상태를 확인해 보자.

피자를 가방에 넣는 데 성공했다! 그러나 식은 피자 조각에만 존재하던 '청결' 스테이터스는 가방에 적용할 수 없었다. 이 경우 리스트나 시리즈 형태로 열 추가를 해 주면 된다. backpack2_df['청결']=[None,None,None,None,None,-1] 과 같은 형태로 추가한다.


ii) 리스트를 .loc 기능을 이용하여 데이터프레임에 추가하기

리스트 형태로 추가할 경우, 가방 속 컬럼 순서에 맞춰 리스트를 정렬해야 한다. 

피자 조각을 넣기 전의 가방 모양을 다시 확인해 보자.

컬럼 순서는 '가격', '무게', '공격력', '갯수', '방어력' 이다.

주어진 pizza의 딕셔너리 키를 찾아 컬럼 순서에 맞춰 차례로 값을 추출하거나, 데이터가 소량인 경우 직접 입력을 통해 피자 조각의 데이터를 리스트에 정돈할 수 있을 것이다.

리스트에 데이터를 추가하거나 순서를 바꾸는 등의 편집 방법은 별도의 포스트에서 공부하도록 하고, 이곳에서는 완성된 리스트를 추가해 보도록 하자.

# 예제를 위해 가방 복사본 또 만들기
backpack3_df=backpack_df.copy()

# 컬럼 순서에 맞게 가공된 식은 피자 조각 리스트
pizzalist=[5,1,None,1,None]

# .loc로 추가
backpack3_df.loc['식은 피자 조각']=pizzalist

결과는 딕셔너리를 추가한 경우와 동일하다.


iii) 데이터프레임 행을 .append로 기존 데이터프레임에 추가하기

식은 피자 조각의 데이터를 데이터프레임으로 가공한 다음, 가방에 넣어 보자.

데이터프레임으로 변환 후 가방에 추가할 때는, 컬럼 이름과 순서를 맞추지 않아도 에러가 나지 않는다. 물론, 불필요한 컬럼의 데이터를 추가 전에 정리해 주는 편이 좋다. append() 명령어로 기존 데이터프레임에 이미 있는 이름의 인덱스를 추가할 경우, 덮어쓰지 않고 새로운 행이 추가된다.

데이터프레임.append(데이터프레임)

우선 pizza를 데이터프레임으로 변환하고, 컬럼을 수정한다.

# 식은 피자 조각의 원 데이터
pizza={'이름':'식은 피자 조각','가격':5,'무게':1,'EA':1, '청결':-1}

# 데이터프레임으로 변환 : DataFrame(딕셔너리, index=['인덱스 이름'])
pizza_df=DataFrame(pizza, index=['식은 피자 조각'])

# 컬럼 이름 변경, 불필요한 컬럼 제거
pizza_df.drop(['이름'], axis=1, inplace=True)
pizza_df.rename(columns={'EA':'갯수'}, inplace=True)

데이터프레임으로 저장된 pizza_df의 데이터.

이 데이터를 .append() 로 추가하자.

# 가방에 피자를 추가한 상태를 backpack4_df 에 저장
backpack4_df=backpack_df.append(pizza_df)

 피자를 넣은 가방 backpack4_df 의 상태. '청결' 컬럼이 추가된 것을 확인할 수 있다.

  • 인덱스와 컬럼 순서 바꾸기

리오는 가방에 들어 있는 아이템을 조금 더 보기 편하게 분류하고 싶어졌다.

.reindex ( columns = [ '컬럼1', '컬럼2', ... ] , index= [ '인덱스1', '인덱스2', ... ] ) 
를 이용하면 지정한 리스트 순서대로 정렬된다. columns, index 파라미터 중 어느 한쪽은 생략해도 무방하다.

컬럼이나 인덱스 내에, 기존 데이터프레임에 존재하지 않는 값을 넣으면 새로운 컬럼과 인덱스가 None 값을 갖고 추가된다.

또한 이미 존재하는 컬럼이나 인덱스를 리스트에 할당하지 않으면 reindex 된 데이터프레임에는 등장하지 않는다. (기존 데이터프레임에 저장된 값은 남아 있다.)

 가방의 컬럼을, 비슷한 종류의 능력치들이 가까이 위치하도록 다시 배치하고, 새롭게 '회복량' 컬럼을 추가해 보도록 하자. '청결' 능력치는 보이지 않도록 하자.

# 컬럼과 인덱스 재정렬 .reindex(columns=[], index=[])
backpack5 = backpack4_df.reindex(columns=['공격력','방어력','회복량','무게','가격','갯수'])

복사된 가방 backpack5에 저장된 아이템 데이터는 다음과 같다.

이것으로, 리오는 식은 피자 조각의 모든 토핑을 유실 없이 가방에 넣는 데에 성공했다! (빠밤!)


요약 :

1. 가방 속 아이템의 분류 태그(컬럼)를 수정하고, 아이템 앞에 붙은 번호표(인덱스)에 아이템 이름을 적은 뒤 원래의 이름표를 떼어냈다.

2. 리스트, 딕셔너리, 데이터프레임의 세 가지 형식을 이용하여 피자 조각을 가방에 성공적으로 추가하였다.

3. 컬럼과 인덱스의 순서를 정렬하고, 일부 컬럼을 보이지 않게 숨기고, 새로운 컬럼을 보이게 하였다.

자욱님의 창작활동을 응원하고 싶으세요?