본문 바로가기
Python/Pandas

[Pandas] 판다스 인덱싱 (loc, iloc)

by 인사이티드 2023. 2. 4.

판다스의 Series와 Dataframe 데이터 구조는 각각 1차원과 2차원이다. 각각은 Python의 [] 기호를 통해서 인덱싱도 가능하지만 .loc과 .iloc을 사용하여 인덱싱 하는 것이 훨씬 편리하다. Python에서 리스트 객체에 사용하는 일반적인 [] 인덱싱은 Series와 Dataframe에서는 오류가 날 가능성이 있기 때문에 loc과 iloc을 사용하는 것이 좋다. 자세한 사례는 stackoverflow에 올라온 질문을 통해 확인해 볼 수 있다.

https://stackoverflow.com/questions/38886080/python-pandas-series-why-use-loc

 

Python: Pandas Series - Why use loc?

Why do we use 'loc' for pandas dataframes? it seems the following code with or without using loc both compile anr run at a simulular speed %timeit df_user1 = df.loc[df.user_id=='5561'] 100 loops,...

stackoverflow.com


위의 내용을 정리해보면 그렇다.
1. row나 column 이름이 True 같은 Boolean 값이면 Dataframe에서 loc없이 인덱싱할 경우 ValueError 오류가 날 수 있다.
2. loc과 iloc을 사용한 인덱싱 방법이 일반적인 인덱싱보다 훨씬 빠르다.

loc과 iloc은 이렇듯 장점이 확실하고 편리한 인덱싱 방법이다. 그렇다면 둘은 어떻게 사용하고 둘의 차이점은 무엇일까?

1. loc
.loc은 주로 레이블 기반으로 사용하고, 불리언 값으로 사용도 가능한 인덱싱 방법이다.

df = pd.read_csv('/content/drive/MyDrive/ML_Data/titanic/train.csv')
df.loc[:]
=>
	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
2	3	1	3	Heikkinen, Miss. Laina	female	26.0	0	0	STON/O2. 3101282	7.9250	NaN	S
3	4	1	1	Futrelle, Mrs. Jacques Heath (Lily May Peel)	female	35.0	1	0	113803	53.1000	C123	S
4	5	0	3	Allen, Mr. William Henry	male	35.0	0	0	373450	8.0500	NaN	S
...	...	...	...	...	...	...	...	...	...	...	...	...
886	887	0	2	Montvila, Rev. Juozas	male	27.0	0	0	211536	13.0000	NaN	S
887	888	1	1	Graham, Miss. Margaret Edith	female	19.0	0	0	112053	30.0000	B42	S
888	889	0	3	Johnston, Miss. Catherine Helen "Carrie"	female	NaN	1	2	W./C. 6607	23.4500	NaN	S
889	890	1	1	Behr, Mr. Karl Howell	male	26.0	0	0	111369	30.0000	C148	C
890	891	0	3	Dooley, Mr. Patrick	male	32.0	0	0	370376	7.7500	NaN	Q
891 rows × 12 columns


1.1. 기본적인 인덱싱 방법
다음과 같이 인덱싱하면 인덱스 기준(row 기준)으로 인덱싱할 수 있다.

df.loc[0:5]
=>
	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
2	3	1	3	Heikkinen, Miss. Laina	female	26.0	0	0	STON/O2. 3101282	7.9250	NaN	S
3	4	1	1	Futrelle, Mrs. Jacques Heath (Lily May Peel)	female	35.0	1	0	113803	53.1000	C123	S
4	5	0	3	Allen, Mr. William Henry	male	35.0	0	0	373450	8.0500	NaN	S
5	6	0	3	Moran, Mr. James	male	NaN	0	0	330877	8.4583	NaN	Q

df.loc[[0,2]]
=>
	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


인덱스가 integer가 아니라면 (예를 들어, string 타입) 다음과 같은 방식으로 인덱싱할 수 있다.

s1 = pd.Series(np.random.randn(6), index=list('abcdef'))
s1.loc['c':]
=>
c   -2.462258
d   -2.733875
e   -1.487532
f    2.144902
dtype: float64


인덱스 기준(row 기준)과 컬럼 기준(column 기준) 모두 혼합해서 인덱싱도 가능하다.

df.loc[0:5,'Name':]
=>

	Name	Sex	Age	SibSp	Parch	Ticket	Fare	Cabin	Embarked
0	Braund, Mr. Owen Harris	male	22.0	1	0	A/5 21171	7.2500	NaN	S
1	Cumings, Mrs. John Bradley (Florence Briggs Th...	female	38.0	1	0	PC 17599	71.2833	C85	C
2	Heikkinen, Miss. Laina	female	26.0	0	0	STON/O2. 3101282	7.9250	NaN	S
3	Futrelle, Mrs. Jacques Heath (Lily May Peel)	female	35.0	1	0	113803	53.1000	C123	S
4	Allen, Mr. William Henry	male	35.0	0	0	373450	8.0500	NaN	S
5	Moran, Mr. James	male	NaN	0	0	330877	8.4583	NaN	Q


1.2. 불리언 인덱싱
판다스의 인덱싱은 불리언 인덱싱 기능도 제공한다.
아래와 같은 방법으로 .loc 불리언 인덱싱이 가능하다.

df.loc[df['Age'] > 25, 'Ticket':]
=>
	Ticket	Fare	Cabin	Embarked
1	PC 17599	71.2833	C85	C
2	STON/O2. 3101282	7.9250	NaN	S
3	113803	53.1000	C123	S
4	373450	8.0500	NaN	S
6	17463	51.8625	E46	S
...	...	...	...	...
883	C.A./SOTON 34068	10.5000	NaN	S
885	382652	29.1250	NaN	Q
886	211536	13.0000	NaN	S
889	111369	30.0000	C148	C
890	370376	7.7500	NaN	Q

여러 개의 조건으로 불리언 인덱싱을 하고 싶을 때에는 반드시 괄호를 사용하여 구분해 주어야 한다.

df.loc[(df['Age'] > 25) & (df['Sex'] == 'male'), 'Ticket':]
=>

		  Ticket	Fare	Cabin	Embarked
4		  373450	8.0500	NaN	S
6		  17463		51.8625	E46	S
13		  347082	31.2750	NaN	S
20		  239865	26.0000	NaN	S
21		  248698	13.0000	D56	S
...	...	...	...	...
881		  349257	7.8958	NaN	S
883	C.A./SOTON 34068	10.5000	NaN	S
886		  211536	13.0000	NaN	S
889		  111369	30.0000	C148	C
890		  370376	7.7500	NaN	Q

만약 괄호를 사용하지 않는다면 아래처럼 오류가 난다.

df.loc[df['Age'] > 25 & df['Sex'] == 'male', 'Ticket':]
=>
TypeError: Cannot perform 'rand_' with a dtyped [object] array and scalar of type [bool]


1.3. 값 변경하기
loc과 iloc은 모두 인덱싱으로 데이터를 조회할 뿐만 아니라 값의 변경도 가능하다.

df['Age'] = 0
df
=>
	PassengerId	Survived	Pclass	Name	Sex	Age	SibSp	Parch	Ticket	Fare	Cabin	Embarked
0	1	0	3	Braund, Mr. Owen Harris	male	0	1	0	A/5 21171	7.2500	NaN	S
1	2	1	1	Cumings, Mrs. John Bradley (Florence Briggs Th...	female	0	1	0	PC 17599	71.2833	C85	C
2	3	1	3	Heikkinen, Miss. Laina	female	0	0	0	STON/O2. 3101282	7.9250	NaN	S
3	4	1	1	Futrelle, Mrs. Jacques Heath (Lily May Peel)	female	0	1	0	113803	53.1000	C123	S
4	5	0	3	Allen, Mr. William Henry	male	0	0	0	373450	8.0500	NaN	S
...	...	...	...	...	...	...	...	...	...	...	...	...
886	887	0	2	Montvila, Rev. Juozas	male	0	0	0	211536	13.0000	NaN	S
887	888	1	1	Graham, Miss. Margaret Edith	female	0	0	0	112053	30.0000	B42	S
888	889	0	3	Johnston, Miss. Catherine Helen "Carrie"	female	0	1	2	W./C. 6607	23.4500	NaN	S
889	890	1	1	Behr, Mr. Karl Howell	male	0	0	0	111369	30.0000	C148	C
890	891	0	3	Dooley, Mr. Patrick	male	0	0	0	370376	7.7500	NaN	Q
# Age column이 전부 다 0으로 변경된 것을 볼 수 있다.


좀 더 세부적인 인덱싱을 통해 원하는 행과 열만 골라내어 값 변경도 가능하다.

df.loc[100:300, 'Sex'] = None
df.loc[95:300]
=>
	PassengerId	Survived	Pclass	Name	Sex	Age	SibSp	Parch	Ticket	Fare	Cabin	Embarked
95	96	0	3	Shorney, Mr. Charles Joseph	male	0	0	0	374910	8.0500	NaN	S
96	97	0	1	Goldschmidt, Mr. George B	male	0	0	0	PC 17754	34.6542	A5	C
97	98	1	1	Greenfield, Mr. William Bertram	male	0	0	1	PC 17759	63.3583	D10 D12	C
98	99	1	2	Doling, Mrs. John T (Ada Julia Bone)	female	0	0	1	231919	23.0000	NaN	S
99	100	0	2	Kantor, Mr. Sinai	male	0	1	0	244367	26.0000	NaN	S
...	...	...	...	...	...	...	...	...	...	...	...	...
296	297	0	3	Hanna, Mr. Mansour	None	0	0	0	2693	7.2292	NaN	C
297	298	0	1	Allison, Miss. Helen Loraine	None	0	1	2	113781	151.5500	C22 C26	S
298	299	1	1	Saalfeld, Mr. Adolphe	None	0	0	0	19988	30.5000	C106	S
299	300	1	1	Baxter, Mrs. James (Helene DeLaudeniere Chaput)	None	0	0	1	PC 17558	247.5208	B58 B60	C
300	301	1	3	Kelly, Miss. Anna Katherine "Annie Kate"	None	0	0	0	9234	7.7500	NaN	Q


2. iloc
.iloc은 정수 인덱스 포지션을 기반으로 인덱싱하는 방법이다. (개인적으로 .loc보다 편리해서 자주 사용하고 있는 인덱싱 기법이다.) 아래는 인덱스와 컬럼을 지정해서 인덱싱한 경우이다.

df.iloc[3,3] # 3번째 인덱스와 3번째 컬럼(Name)의 값
=> 'Futrelle, Mrs. Jacques Heath (Lily May Peel)'

df.iloc[1:5,3:5] # 1~4번째 인덱스와 3~4번째 컬럼의 값. 데이터프레임을 리턴한다.
=>
	Name							Sex
1	Cumings, Mrs. John Bradley (Florence Briggs Th...	female
2	Heikkinen, Miss. Laina					female
3	Futrelle, Mrs. Jacques Heath (Lily May Peel)		female
4	Allen, Mr. William Henry				male

df.iloc[[2,5,7],[3,6]] # integer 배열
=>
	Name				SibSp
2	Heikkinen, Miss. Laina		0
5	Moran, Mr. James		0
7	Palsson, Master. Gosta Leonard	3

.iloc도 마찬가지로 데이터에 접근하여 값 변경이 가능하다.

df.iloc[2:4, [3,6]] = 0 # Name, SibSp 컬럼의 2~4번째 인덱스 값을 0으로 변경 
df.head()
=>
PassengerId	Survived	   Pclass	Name	Sex	Age	SibSp	Parch	Ticket	Fare	Cabin	Embarked
0	1		0		3	Braund, Mr. Owen Harris	male	0	1	0	A/5 21171	7.2500	NaN	S
1	2		1		1	Cumings, Mrs. John Bradley (Florence Briggs Th...	female	0	1	0	PC 17599	71.2833	C85	C
2	3		1		3	0	female	0	0	0	STON/O2. 3101282	7.9250	NaN	S
3	4		1		1	0	female	0	0	0	113803	53.1000	C123	S
4	5		0		3	Allen, Mr. William Henry	male	0	0	0	373450	8.0500	NaN	S

참고자료

[1] Runner Bean, "Pandas: Pandas Series - Why use loc?", stackoverflow, https://stackoverflow.com/questions/38886080/python-pandas-series-why-use-loc

[2] "User Guide: Indexing and selecting data" , Pandas, https://pandas.pydata.org/docs/user_guide/indexing.html