Pandas 기본기 | 행과 열의 선택

pandas
Author

강신성

Published

2023-10-10

pandas에서 행과 열을 선택하는 기술에 대해서 알아보도록 하자!

해당 포스트는 전북대학교 통계학과 최규빈 교수님의 강의내용을 토대로 재구성되었음을 알립니다.

1. 라이브러리 import

import numpy as np
import pandas as pd

2. pandas : 행과 열의 선택

- 같은 자료, 다른 두 형태의 데이터프레임

df = pd.DataFrame({'date': ['12/30','12/31','01/01','01/02','01/03'], 'X1': [65,95,65,55,80], 'X2': [55,100,90,80,30], 'X3': [50,50,60,75,30], 'X4': [40,80,30,80,100]})
df
date X1 X2 X3 X4
0 12/30 65 55 50 40
1 12/31 95 100 50 80
2 01/01 65 90 60 30
3 01/02 55 80 75 80
4 01/03 80 30 30 100

얘는 인덱스는 그저 숫자의 의미이고

ts = pd.DataFrame({'X1': [65,95,65,55,80], 'X2': [55,100,90,80,30], 'X3': [50,50,60,75,30], 'X4': [40,80,30,80,100]}, index=['12/30','12/31','01/01','01/02','01/03'])
ts  ## 중요한 코드는 아님, 근데 그냥 index 지정해주는 거잖아
X1 X2 X3 X4
12/30 65 55 50 40
12/31 95 100 50 80
01/01 65 90 60 30
01/02 55 80 75 80
01/03 80 30 30 100

얘는 인덱스에 시계열적 표현이 있다.

ts.reset_index()  ## 결국 이렇게 하는 게 다루기 편하다.
index X1 X2 X3 X4
0 12/30 65 55 50 40
1 12/31 95 100 50 80
2 01/01 65 90 60 30
3 01/02 55 80 75 80
4 01/03 80 30 30 100

안바꾸고 냅두는 경우, index가 time seat를 의미하는 경우에는 안바꾸기도 한다. ~근데 위는 왜 다시 바꾼거~

A. 열의 선택

  • 1번째 방법 : df.ㆍ

    ! 치명적인 단점 : 변수 이름에 공백 등이 있으면 불러올 수 없음.

df.X1   ## df 또한 하나의 object이므로
0    65
1    95
2    65
3    55
4    80
Name: X1, dtype: int64
  • 2번째 방법 : df['ㆍ'], df[['ㆍ']]
df['X1']  ## df를 일종의 딕셔너리처럼 취급하는 방법
0    65
1    95
2    65
3    55
4    80
Name: X1, dtype: int64

Series로 불러온다.

dictionary?

dct = dict({'date': ['12/30','12/31','01/01','01/02','01/03'], 'X1': [65,95,65,55,80], 'X2': [55,100,90,80,30], 'X3': [50,50,60,75,30], 'X4': [40,80,30,80,100]})
dct['X1']
[65, 95, 65, 55, 80]
df.keys()
Index(['date', 'X1', 'X2', 'X3', 'X4'], dtype='object')
dct.keys()
dict_keys(['date', 'X1', 'X2', 'X3', 'X4'])

key와 value가 있는 것처럼 column의 한 값(key)에 대한 데이터(value)가 있는 모습이다.

df[['X1']]  ## 프레임으로 산출
X1
0 65
1 95
2 65
3 55
4 80
df[['X1', 'X2']]  ## 2개 이상 산출 가능
X1 X2
0 65 55
1 95 100
2 65 90
3 55 80
4 80 30
  • 3번째 방법 : df.iloc[:, ㆍ] > 통째로 np.array와 같다고 보면 된다.
df.iloc[:, 0] ## numpy에서 행렬을 다루는 것과 완전히 같게 사용 가능.
0    12/30
1    12/31
2    01/01
3    01/02
4    01/03
Name: date, dtype: object
#df.iloc[:,0] ## int - 0번째 행 | [0]이면 데이터프레임으로
#df.iloc[:,-2:] # int:int, -2번째 행부터 -1번째 행까지(뒤에서 두 개)
#df.iloc[:,1::2] # int:int:int - 스트라이딩, 1번째(두번째) 행부터 2개 단위로 추출
#df.iloc[:,[0,2]] # [int,int] - 특정 행(0, 2번째)을 데이터프레임의 형태로 반환
#df.iloc[:,[True,True,False,False,False]] # bool의 list
#df.iloc[:,range(2)] # range, 앞에서 2개
  • 4번째 방법 : df.loc[:, ㆍ] > 완전히 새로운 방법
#df.loc[:,'X1'] # str - 시리즈 | ['X1']이면 데이터프레임으로
#df.loc[:,'X1':'X3'] # 'str':'str' -- 칼럼이름으로 슬라이싱 **
#df.loc[:,'X1'::2] # 'str'::int -- 칼럼이름으로 스트라이딩 **
#df.loc[:,['X1','X4']] # [str,str] - 특정 행만 데이터프레임으로
#df.loc[:,[True,False,False,True,False]] # bool의 list

"""
그냥 왠만해선 다 됨
"""

- 'date'행 부터

df.loc[:, 'date':]
date X1 X2 X3 X4
0 12/30 65 55 50 40
1 12/31 95 100 50 80
2 01/01 65 90 60 30
3 01/02 55 80 75 80
4 01/03 80 30 30 100

- True가 입력된 행만

df.loc[:, [True, False, True, False, True]]   ## columns의 이름에 어떤 조건을 걸어서 True에 해당하는 열만 산출 가능
date X2 X4
0 12/30 55 40
1 12/31 100 80
2 01/01 90 30
3 01/02 80 80
4 01/03 30 100

- 2칸씩 띄며 스트라이딩

df.loc[:, ::2]  ## 2 간격으로 스트라이딩
date X2 X4
0 12/30 55 40
1 12/31 100 80
2 01/01 90 30
3 01/02 80 80
4 01/03 30 100

B. 행의 선택

  • 방법1 : df[]
df[:2]    ## int:int -- 슬라이싱 // df.iloc[:2, :], df.iloc[:2] 와 같음
date X1 X2 X3 X4
0 12/30 65 55 50 40
1 12/31 95 100 50 80
df[::2]  ## 스트라이딩, df.iloc[::2]와 같음
date X1 X2 X3 X4
0 12/30 65 55 50 40
2 01/01 65 90 60 30
4 01/03 80 30 30 100
# df[:2] # int:int -- 슬라이싱 // df.iloc[:2,:], df.iloc[:2] 와 같음
# df[::2] # int:int -- 스트라이딩
# ts['12/30':'01/02'] # str:str -- 슬라이싱 > 인덱스가 문자열 등일 경우
# ts['12/31'::2] # str:str -- 스트라이딩
# df[['12' in date for date in df.date]] # [bool,bool] `12`가 데이터에 포함되어 있을 경우
# df[df.X1 < 70] # pd.Series([bool,bool])
  • 방법2 : df.iloc[]
# df.iloc[0] # int  df.iloc[0, :]에서 생략된 표현
# df.iloc[-2:] # int:int -- 슬라이싱
# df.iloc[1::2] # int:int -- 스트라이딩
# df.iloc[[0]] # [int]
# df.iloc[[0,1]] # [int,int]
# df.iloc[['12' in date for date in df.date]] # [bool,bool] 이 경우는 []와 동일하다.
# df.iloc[range(2)] # range

- 해당 방법은 리스트나 어레이의 원소를 다루는 것과 완전히 동일해서… 아래를 참고하면 된다.

lst = [[1,2,3], [3,4,5]]
lst[0]
[1, 2, 3]
ary = np.array(lst)
ary[0]
array([1, 2, 3])
  • 방법3 : df.loc[]
# df.loc[0] # int 
# ts.loc['12/30'] # str 
# df.loc[:2] # int:int 
# ts.loc[:'01/02'] # str:str 
# df.loc[[0,1]] # [int,int]
# ts.loc[['12/30','01/01']] # [str,str]
# df.loc[['12' in date for date in df.date]] # [bool,bool] 이 경우는 []와 동일하다.
# df.loc[df.X1>70] # pd.Series([bool,bool]) 
df.loc[:2]  ## character와 비슷한 형식이기 때문에 2까지 포함이 된다.
date X1 X2 X3 X4
0 12/30 65 55 50 40
1 12/31 95 100 50 80
2 01/01 65 90 60 30
df.loc[df.X1 > 70]
date X1 X2 X3 X4
1 12/31 95 100 50 80
4 01/03 80 30 30 100
df.loc[df.X1 > 70]
date X1 X2 X3 X4
1 12/31 95 100 50 80
4 01/03 80 30 30 100

위처럼 튜플로 넣을 수도 있다. 근데 iloc의 경우 위와 같은 코드로 입력하면 오류가 난다.

## df.iloc[df.X1 > 70] > 오류, bool을 받을 수 있으나, 튜플의 형태로 들어가면 반환하지 않는다.
df.iloc[list(df.X1 > 70)]
date X1 X2 X3 X4
1 12/31 95 100 50 80
4 01/03 80 30 30 100

D. 교수님 방식

-가장 안전한 코드

df.loc[:,:] ## 해당 코드를 써놓고 시작, generally
date X1 X2 X3 X4
0 12/30 65 55 50 40
1 12/31 95 100 50 80
2 01/01 65 90 60 30
3 01/02 55 80 75 80
4 01/03 80 30 30 100
  1. 하나의 col을 뽑으려 할 때
# df.X1       ## 제일 간단함. 게다가 눌러보면 변수 이름들이 나옴
# df['X1']
# df[['X1']]
  1. row를 슬라이싱
# df[:5]
# ts[:'01/02']  # 시계열일 경우
  1. 조건에 맞는 row를 뽑을 때 좋은 코드
# df[df.X1<60]  ## 이게 좋기는 한데, True, False를 직접 만들어야 하는 경우도 많음.
# df.loc[['12' in date for date in df.date]]
['12' in date for date in df.date]
[True, True, False, False, False]
  1. 하나의 row를 뽑으려 할 때 좋은 코드
# df.iloc[0]
# df.loc[0]
ts.iloc[[0]]
# ts.iloc[0]의 경우 오류가 남(인덱스 이름이 숫자열이 아님
X1 X2 X3 X4
12/30 65 55 50 40
  1. (row,col)을 뽑으려 할 때 좋은 코드
# df.X1[0]    ## <- pd.Series를 뽑고 인덱스로 접근
# df['X1'][0]


# df.iloc[0,0]
# df.loc[0,'X1']

*위의 상황 이외에는 df.loc[:,:]를 사용하는 것이 유리하다.

요약

  • 알아두면 좋은 규칙

  • .iloc[] 와 .iloc[,:]는 완전히 동등하다.

  • .loc[] 와 .loc[,:]는 완전히 동등하다.

  • 결과를 pd.Series 형태가 아닌 pd.DataFrame 형태로 얻고 싶다면 [[?]]를 사용하면 된다.

ROW

type of indexer . [] .iloc .loc 내가 쓴다면?
int X X O \(\Delta\) df.iloc[3,:]
int:int X O O \(\Delta\) df[3:5]
[int,int] X X O \(\Delta\) df.iloc[idx,:]
str X X X O ts.loc['time1',:]
str:str X O X O ts.loc['time1':'time2',:]
[str,str] X X X O 안할 듯
[bool,bool] X O O O df[filtered_idx]
pd.Series([bool,bool]) X O X O df[df.X1>20]

COL

type of indexer target . [] .iloc .loc 내가 쓴다면?
int col X X O X df.iloc[:,0]
int:int col X X O X df.iloc[:,0:2]
[int,int] col X X O X df.iloc[:,idx]
str col O O X O df.loc[:,'X1']
str:str col X X X O df.loc[:,'X1':'X4']
[str,str] col X O X O df.loc[:,colname_list]
[bool,bool] col X X O O df.loc[:,bool_list]