데이터 셀렉션 및 필터링

CharliePark·2020년 9월 7일
0

TIL

목록 보기
27/67

 

데이터 셀렉션 및 필터링

 

DataFrame의 [ ] 연산자

[ ] 안에 행의 위치, 열의 위치, 슬라이싱 범위 등을 지정할 수 있었던 NumPy와 달리, DataFrame의 [ ] 연산자 안에는 칼럼명 문자 또는 인덱스로 변환 가능한 표현식만 들어갈 수 있다.

인덱스로 변환 가능한 표현식은 추후에 다루고, 칼럼명을 지정하는 예시만 들어보자.

import pandas as pd
import numpy as np
titanic_df = pd.read_csv('titanic_train.csv')
print('단일 컬럼 데이터 추출:\n', titanic_df[ 'Pclass' ].head(3))
print('\n여러 컬럼들의 데이터 추출:\n', titanic_df[ ['Survived', 'Pclass'] ].head(3))
print('[ ] 안에 숫자 index는 KeyError 오류 발생:\n', titanic_df[0])

output

단일 컬럼 데이터 추출:
 0    3
1    1
2    3
Name: Pclass, dtype: int64

여러 컬럼들의 데이터 추출:
    Survived  Pclass
0         0       3
1         1       1
2         1       3



---------------------------------------------------------------------------

KeyError                                  Traceback (most recent call last)


During handling of the above exception, another exception occurred:


KeyError                                  Traceback (most recent call last)

 

 

 

titanic_df[0], titanic_df[[0, 1, 2]] 와 같이 칼럼명이 아닌 것을 지정하면 오류가 발생한다

이때, 슬라이싱과 같이 인덱스로 변환 가능한 표현식 은 정상적으로 작동한다

titanic_df[0:2]

output

PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.2500 NaN S
1 2 1 1 Cumings, Mrs. John Bradley (Florence Briggs Th... female 38.0 1 0 PC 17599 71.2833 C85 C

 

 

 

또한 불린 인덱싱 표현도 가능하고, 빈번하게 사용된다.

아래 예제에서는 Pclass 칼럼 값이 3인 데이터를 3개만 추출한다.

titanic_df[ titanic_df['Pclass'] == 3].head(3)

output

PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
0 1 0 3 Braund, Mr. Owen Harris male 22.0 1 0 A/5 21171 7.250 NaN S
2 3 1 3 Heikkinen, Miss. Laina female 26.0 0 0 STON/O2. 3101282 7.925 NaN S
4 5 0 3 Allen, Mr. William Henry male 35.0 0 0 373450 8.050 NaN S

 

 

[ ] 연산자에 대해 정리하자면 아래와 같다

  • DataFrame 바로 뒤의 [ ] 연산자는 넘파이의 [ ]나 Series의 [ ]와 다르다.
  • DataFrame 바로 뒤의 [ ] 내 입력 값은 칼럼명을 사용하거나, 불린 인덱스로만 사용해야 한다
  • DataFrame[0:2] 와 같은 슬라이싱은 사용가능하나, 사용하지 않는 것이 좋다.

 

 

DataFrame ix[ ] 연산자

ix[ ] 연산자는 칼럼 명칭(label)기반 인덱싱 (ix[0, 'Pclass'])과 칼럼 위치(position)기반 인덱싱 (ix[0,2])를 모두 제공하게 되면서, 코드에 혼돈을 주거나 가독성이 떨어진다는 이유로 현재는 Pandas에서 사라지게(deprecated) 되었다.

이를 대체하기 위해 loc[ ] 이라는 칼럼 명칭 기반 인덱싱 연산자와 iloc[ ] 이라는 칼럼 위치 기반 인덱싱 연산자가 만들어졌다.

아직 ix[ ] 는 사용 가능하나(Deprecation Warning), 향후 사라질 예정이다.

 

print('컬럼 위치 기반 인덱싱 데이터 추출:',titanic_df.ix[0,2])
print('컬럼명 기반 인덱싱 데이터 추출:',titanic_df.ix[0,'Pclass'])

output

컬럼 위치 기반 인덱싱 데이터 추출: 3
컬럼명 기반 인덱싱 데이터 추출: 3


.ix is deprecated. Please use
.loc for label based indexing or
.iloc for positional indexing

See the documentation here:
http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#ix-indexer-is-deprecated

  

 

 

ix[] 연산자는 넘파이 ndarray의 [ ]연산자와 동일하게 단일 지정, 슬라이싱, 불린 인덱싱, 팬시 인덱싱 모두 가능하다.

data = {'Name': ['Chulmin', 'Eunkyung','Jinwoong','Soobeom'],
        'Year': [2011, 2016, 2015, 2015],
        'Gender': ['Male', 'Female', 'Male', 'Male']
       }
data_df = pd.DataFrame(data, index=['one','two','three','four'])
data_df

output

Name Year Gender
one Chulmin 2011 Male
two Eunkyung 2016 Female
three Jinwoong 2015 Male
four Soobeom 2015 Male

 

 

 

print("\n ix[0,0]", data_df.ix[0,0])
print("\n ix['one', 0]", data_df.ix['one',0])
print("\n ix[3, 'Name']",data_df.ix[3, 'Name'],"\n")

print("\n ix[0:2, [0,1]]\n", data_df.ix[0:2, [0,1]])
print("\n ix[0:2, [0:3]]\n", data_df.ix[0:2, 0:3])
print("\n ix[0:3, ['Name', 'Year']]\n", data_df.ix[0:3, ['Name', 'Year']], "\n")
print("\n ix[:] \n", data_df.ix[:])
print("\n ix[:, :] \n", data_df.ix[:, :])

print("\n ix[data_df.Year >= 2014] \n", data_df.ix[data_df.Year >= 2014])

output

 ix[0,0] Chulmin

 ix['one', 0] Chulmin

 ix[3, 'Name'] Soobeom 


 ix[0:2, [0,1]]
          Name  Year
one   Chulmin  2011
two  Eunkyung  2016

 ix[0:2, [0:3]]
          Name  Year  Gender
one   Chulmin  2011    Male
two  Eunkyung  2016  Female

 ix[0:3, ['Name', 'Year']]
            Name  Year
one     Chulmin  2011
two    Eunkyung  2016
three  Jinwoong  2015 


 ix[:] 
            Name  Year  Gender
one     Chulmin  2011    Male
two    Eunkyung  2016  Female
three  Jinwoong  2015    Male
four    Soobeom  2015    Male

 ix[:, :] 
            Name  Year  Gender
one     Chulmin  2011    Male
two    Eunkyung  2016  Female
three  Jinwoong  2015    Male
four    Soobeom  2015    Male

 ix[data_df.Year >= 2014] 
            Name  Year  Gender
two    Eunkyung  2016  Female
three  Jinwoong  2015    Male
four    Soobeom  2015    Male



.ix is deprecated. Please use
.loc for label based indexing or
.iloc for positional indexing

See the documentation here:
http://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#ix-indexer-is-deprecated

 

 

 

명칭 기반 인덱싱과 위치 기반 인덱싱의 구분

명칭(label) 기반 인덱싱은 칼럼의 명칭을 기반으로 위치를 지정하는 방식이다. 위치(Position) 기반 인덱싱은 0을 출발점으로 하는 가로축, 세로축 좌표 지반의 행과 열 위치를 기반으로 데이터를 지정한다.

DataFrame의 인덱스 값은 명칭 기반 인덱싱으로 간주해야 한다. ix[ ] 는 명칭 기반, 위치 기반 인덱싱을 모두 허용하므로 위치 기반 인덱싱이 integer 형일 때 코드에 혼란을 초래한다.

이에 loc[ ] 이라는 칼럼 명칭 기반 인덱싱 연산자와 iloc[ ]* 이라는 칼럼 위치 기반 인덱싱 연산자를 사용하여 구분을 명확히 한다.

 

 

DataFrame iloc[ ] 연산자

iloc[ ] 는 위치 기반 인덱싱만 허용하기 때문에 행과 열 값으로 integer 또는 integer 형의 슬라이싱, 팬시 리스트 값을 입력해줘야 한다.

data_df.iloc[0, 0]

output

'Chulmin'

 

 

iloc[ ] 에 위치 인덱싱이 아닌 명칭을 입력하면 오류가 발생한다.

# 아래 코드는 오류를 발생합니다. 
data_df.iloc[0, 'Name']

output

---------------------------------------------------------------------------



ValueError: Location based indexing can only have [integer, integer slice (START point is INCLUDED, END point is EXCLUDED), listlike of integers, boolean array] types

마찬가지로 문자열 인덱스를 입력해도 오류가 발생한다.

# 아래 코드는 오류를 발생합니다. 
data_df.iloc['one', 0]

output

--------------------------------------------------------------------------
ValueError: Location based indexing can only have [integer, integer slice (START point is INCLUDED, END point is EXCLUDED), listlike of integers, boolean array] types

iloc[ ] 은 슬라이싱과 팬시 인덱싱은 제공하나 명확한 위치 기반 인덱싱이 사용되어야 하는 제약으로 인해 불린 인덱싱은 제공하지 않는다.

 

DataFrame loc[ ] 연산자

loc[ ] 는 명칭 기반으로 데이터를 추출한다. 따라서 행 위치에는 DataFrame index 값을, 그리고 열 위치에는 칼럼 명을 입력해줘야 한다.

 

data_df

output

Name Year Gender
one Chulmin 2011 Male
two Eunkyung 2016 Female
three Jinwoong 2015 Male
four Soobeom 2015 Male

 

 

data_df.loc['one', 'Name']

output

'Chulmin'

 

 

인덱스가 숫자 형일 수 있기 때문에, 꼭 명칭에 문자열만 들어가는 것은 아니다.

인덱스를 1부터 시작하는 자연수로 reset하고, 0번째 인덱스를 호출하면 인덱스 값이 0인 행이 없으므로 오류가 발생한다.

data_df_reset = data_df.reset_index()
data_df_reset.index = data_df_reset.index + 1
data_df_reset

output

index Name Year Gender
1 one Chulmin 2011 Male
2 two Eunkyung 2016 Female
3 three Jinwoong 2015 Male
4 four Soobeom 2015 Male

 

 

data_df_reset.loc[1, 'Name']

output

'Chulmin'

 

 

data_df_reset.loc[0, 'Name']

output

---------------------------------------------------------------------------

ValueError: 0 is not in range

 

 

loc[ ] 에 슬라이싱을 적용할 때는 일반적인 슬라이싱과 달리 범위의 종료값까지 포함이 된다.

print('위치기반 iloc slicing\n', data_df.iloc[0:1, 0],'\n')
print('명칭기반 loc slicing\n', data_df.loc['one':'two', 'Name'])

output

위치기반 iloc slicing
 one    Chulmin
Name: Name, dtype: object 

명칭기반 loc slicing
 one     Chulmin
two    Eunkyung
Name: Name, dtype: object

 

 

이는 loc[ ] 에서 정수형 인덱스값을 사용할 때도 마찬가지이므로 주의해야 한다.

print(data_df_reset.loc[1:2 , 'Name'])

output

1     Chulmin
2    Eunkyung
Name: Name, dtype: object

 

 

 

정리하자면 아래와 같다.

  1. 가장 중요한 것은 명칭 기반 인덱싱과 위치 기반 인덱싱의 차이를 이해하는 것. DataFrame의 인덱스나 칼럼 명으로 데이터에 접근하는 것은 명칭 기반 인덱싱이고, 0부터 시작하는 행, 열의 위치 좌표에 의존하는 것이 위치기반 인덱싱이다.
  2. ix[ ] 는 명칭 기반 인덱싱과 위치 기반 인덱싱을 모두 적용할 수 있다. 인덱스가 숫자형일 경우, 행 위치의 숫자는 명칭 기반 인덱싱으로 작동한다.
  3. iloc[ ] 는 위치 기반 인덱싱만 가능하다.
  4. loc[ ] 는 명칭 기반 인덱싱만 가능하다. 행 위치에 DataFrame 인덱스, 열 위치에 칼럼 명을 넣어주면 된다.
  5. 명칭 기반 인덱싱에서 슬라이싱을 '시작점:종료점' 으로 지정할 때 종료점 위치를 포함하여 데이터를 반환한다.

 

 

 

 

불린 인덱싱

ix, iloc, loc 과 같이 명확히 인덱싱을 지정하는 방식보다는 불린 인덱싱을 이용해 데이터를 가져오는 경우가 더 많다.

불린 인덱싱은 [ ], ix[ ], loc[ ] 에서 공통으로 지원한다. iloc[ ] 은 불린 인덱싱이 지원되지 않는다.

titanic_df = pd.read_csv('titanic_train.csv')
titanic_boolean = titanic_df[titanic_df['Age'] > 60]
print(type(titanic_boolean))
titanic_boolean

output

<class 'pandas.core.frame.DataFrame'>
PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
33 34 0 2 Wheadon, Mr. Edward H male 66.0 0 0 C.A. 24579 10.5000 NaN S
54 55 0 1 Ostby, Mr. Engelhart Cornelius male 65.0 0 1 113509 61.9792 B30 C
96 97 0 1 Goldschmidt, Mr. George B male 71.0 0 0 PC 17754 34.6542 A5 C
116 117 0 3 Connors, Mr. Patrick male 70.5 0 0 370369 7.7500 NaN Q
170 171 0 1 Van der hoef, Mr. Wyckoff male 61.0 0 0 111240 33.5000 B19 S
252 253 0 1 Stead, Mr. William Thomas male 62.0 0 0 113514 26.5500 C87 S
275 276 1 1 Andrews, Miss. Kornelia Theodosia female 63.0 1 0 13502 77.9583 D7 S
280 281 0 3 Duane, Mr. Frank male 65.0 0 0 336439 7.7500 NaN Q
326 327 0 3 Nysveen, Mr. Johan Hansen male 61.0 0 0 345364 6.2375 NaN S
438 439 0 1 Fortune, Mr. Mark male 64.0 1 4 19950 263.0000 C23 C25 C27 S
456 457 0 1 Millet, Mr. Francis Davis male 65.0 0 0 13509 26.5500 E38 S
483 484 1 3 Turkula, Mrs. (Hedwig) female 63.0 0 0 4134 9.5875 NaN S
493 494 0 1 Artagaveytia, Mr. Ramon male 71.0 0 0 PC 17609 49.5042 NaN C
545 546 0 1 Nicholson, Mr. Arthur Ernest male 64.0 0 0 693 26.0000 NaN S
555 556 0 1 Wright, Mr. George male 62.0 0 0 113807 26.5500 NaN S
570 571 1 2 Harris, Mr. George male 62.0 0 0 S.W./PP 752 10.5000 NaN S
625 626 0 1 Sutton, Mr. Frederick male 61.0 0 0 36963 32.3208 D50 S
630 631 1 1 Barkworth, Mr. Algernon Henry Wilson male 80.0 0 0 27042 30.0000 A23 S
672 673 0 2 Mitchell, Mr. Henry Michael male 70.0 0 0 C.A. 24580 10.5000 NaN S
745 746 0 1 Crosby, Capt. Edward Gifford male 70.0 1 1 WE/P 5735 71.0000 B22 S
829 830 1 1 Stone, Mrs. George Nelson (Martha Evelyn) female 62.0 0 0 113572 80.0000 B28 NaN
851 852 0 3 Svensson, Mr. Johan male 74.0 0 0 347060 7.7750 NaN S

 

 

60세 이상인 승객의 나이와 이름만 추출하면 아래와 같다

titanic_df[titanic_df['Age'] > 60][['Name','Age']].head(3)

output

Name Age
33 Wheadon, Mr. Edward H 66.0
54 Ostby, Mr. Engelhart Cornelius 65.0
96 Goldschmidt, Mr. George B 71.0

 

 

loc[ ] 를 이용해도 동일하게 적용할 수 있다.

titanic_df.loc[titanic_df['Age'] > 60, ['Name','Age']].head(3)

output

Name Age
33 Wheadon, Mr. Edward H 66.0
54 Ostby, Mr. Engelhart Cornelius 65.0
96 Goldschmidt, Mr. George B 71.0

 

 

&(and), |(or), ~(not) 을 적용해 여러개의 조건을 복합적으로 사용하는 것도 가능하다

titanic_df[ (titanic_df['Age'] > 60) & (titanic_df['Pclass']==1) & (titanic_df['Sex']=='female')]

output

PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
275 276 1 1 Andrews, Miss. Kornelia Theodosia female 63.0 1 0 13502 77.9583 D7 S
829 830 1 1 Stone, Mrs. George Nelson (Martha Evelyn) female 62.0 0 0 113572 80.0000 B28 NaN

 

 

조건식은 변수로도 할당 가능하다.

cond1 = titanic_df['Age'] > 60
cond2 = titanic_df['Pclass']==1
cond3 = titanic_df['Sex']=='female'
titanic_df[ cond1 & cond2 & cond3]

output

PassengerId Survived Pclass Name Sex Age SibSp Parch Ticket Fare Cabin Embarked
275 276 1 1 Andrews, Miss. Kornelia Theodosia female 63.0 1 0 13502 77.9583 D7 S
829 830 1 1 Stone, Mrs. George Nelson (Martha Evelyn) female 62.0 0 0 113572 80.0000 B28 NaN

0개의 댓글