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 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
정리하자면 아래와 같다.
불린 인덱싱
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 |