Pandas 특정 행 삭제 - Pandas teugjeong haeng sagje

Pandas - DataFrame에서 행 삭제 및 추가

그림자2019. 8. 26. 21:47

이번 글에서는 PythonDataFrame에서 행(row)을 추가 또는 삭제하는 방법을 정리하겠습니다. DataFrame은 데이터 처리할 때 매우 유용하게 사용할 수 있는 데이터 구조이므로, 그 활용 방법을 많이 알아두시면 좋습니다. :)

DataFrame

행과 열로 구성된 파이썬의 2차원 데이터 구조

관계형 DB의 테이블이나 스프레드 시트와 형태 유사

워크맨 재밌음

예제 데이터는 앞서 '특정 행 또는 열 선택하는 방법'에 대해 정리한 글에서 사용한 '공공데이터포털''건강검진정보(2017년)'을 다시 사용하겠습니다. 전에 '가입자일련번호' 열을 index로 읽어왔더니, index 순서와 좀 혼돈될 수 있었던 거 같아서, 이번에는 '가입자일련번호''가입자 ID'로 변경하고 50명에게 ID를 할당하였습니다. :)

pandas'read_excel' 메소드(method)를 이용하여 예제 데이터를 불어 오겠습니다. 먼저 파이썬 라이브러리를 import하고,

import pandas as pd import matplotlib.pyplot as plt

예제 데이터를 불러옵니다. '가입자 ID'를 index로 세팅했습니다.

path_file = r'D:\Python_Pandas' # 파일이 들어 있는 폴더 경로 (변경해서 사용하세요!) fn = 'sample_data_50.xlsx' sn = 'Sheet1' idx_col = '가입자 ID' data = pd.read_excel(path_file + '\\' + fn, sheet_name=sn, index_col=idx_col)

필요없는 열은 빼고, 예제에서 사용할 열만 추려서 'df_sample' 이라는 DataFrame 객체를 만들겠습니다.

# 'DataFrame.loc' 이용해서 사용할 컬럼만 추출 df_sample = data.loc[:, ['성별코드', '연령대코드(5세단위)', '허리둘레', '흡연상태', '음주여부', '식전혈당(공복혈당)', '총콜레스테롤', '수축기혈압']] df_sample.head(10)

DataFrame 행 삭제

drop, delete

DataFrame의 행을 삭제하는 방법은 많이 있겠지만, 주로 사용되는 방법(=제가 아는 방법ㅎㅎ)은 아래와 같이 정리할 수 있을 거 같네요. :)

1. 'dropna' 이용한 결측 데이터 제거

2. 'drop.duplicates' 이용한 중복 제거

3. index명, index 순서 이용해서 행 삭제

4. 조건에 따라 행 삭제

결측 데이터 확인 후 삭제

결측치 제거하기 전에, 사용할 데이터 내에 결측치가 있는지 먼저 확인 해봅니다. 'isnull()' 메소드를 사용하면, 결측치는 True로, 데이터가 있는 경우는 False로 결과를 반환합니다.

하지만 이 방법은 데이터가 커질수록 결측치 확인이 어렵습니다. 마치 값이 엄청 많이 입력된 엑셀에서 빈칸을 찾는 것과 같지요.. 그래서 'sum()'도 같이 사용해줍니다. 이렇게 사용하면, 각 열별로 결측치가 몇 개 있는지 알 수 있습니다. (True 갯수를 합쳐주는 것이지요.)

결과는 다음과 같습니다. 결측치를 확인해본 결과, '허리둘레'에는 3개, '흡연상태''음주여부'에는 1개씩의 결측 데이터가 있군요.

이제 결측치를 처리해보겠습니다. 처리 방법은 1) 결측치가 있는 행이나 열을 통으로 없애버리는 방법과, 2) 빈 곳에 새로운 값을 입력해주고 행이나 열을 그냥 사용하는 방법으로 나눌 수 있습니다. 2번 방법은 'fillna()'라는 메소드를 사용하면 되는데.... 여기선 우선 1번 방법에 대해 좀더 자세히 정리하겠습니다. :)

결측치가 있는 행을 삭제하기 위해서는 'dropna()' 함수를 사용하면 됩니다.

df_sample_1 = df_sample.dropna() df_sample_1.isnull().sum()

'isnull()''sum()'으로 다시 확인해보면, 모든 열에서 NaN이 없어진 것을 확인할 수 있습니다.

번외로, 객체를 새로 선언하지 않고 지금 객체를 업데이트하고 싶을 때에는 ()안에 'inplace=True'를 써주면 됩니다. 이런 식으로요..

df_sample.dropna(inplace=True)

이렇게 사용하면, 'df_sample'에서 바로 결측치가 있는 행이 삭제됩니다.

중복 데이터 확인 후 삭제

중복 데이터 확인에는 'duplicated()' 메소드를 사용합니다. 결과로는 중복된 행들은 True로, 반대의 경우는 False로 반환됩니다. 하지만, 행(row)이 많아지면 일일이 True를 찾을 순 없기에.. 이 경우도 'sum()'을 사용하면 확인이 편합니다.

df_sample_1.duplicated().sum()

중복인 행을 삭제할 때 사용하는 함수는 'drop_duplicates()'입니다.

df_sample_2 = df_sample_1.drop_duplicates() print(df_sample_1.shape) print(df_sample_2.shape)

중복 데이터 삭제 전후인 'df_sample_1''df_sample_2'의 크기를 비교해보면, 5개 행이 차이가 납니다.

'drop_duplicates()' 메소드를 사용할 때도 기존 객체를 그대로 사용하고 싶을 때에는 'inplace=True'를 사용할 수 있습니다.

'index명' 또는 'index 순서'로 행 삭제

여기에서는 'drop()' 함수를 사용합니다.

index명을 사용해서 행을 삭제할 때에는 ()안에 삭제할 행의 이름을 입력하면 됩니다.

df_sample_3 = df_sample_2.drop(['SKP027', 'SKP028']) df_sample_3

index명이 'SKP027''SKP028'인 행이 삭제되었습니다.

index 위치를 이용해서 행을 삭제하는 방법은 다음과 같습니다. 'df_sample_2'에서 'SKP027''SKP028'이 각각 23, 24번째 행이기 때문에, 아래 코드를 실행하면 앞과 동일한 결과를 얻을 수 있습니다.

df_sample_4 = df_sample_2.drop([df_sample_2.index[22], df_sample_2.index[23]])

열(column) 조건에 따라 행 삭제

열 조건에 따라 행을 삭제하는 방법의 기본 원리는 앞서 보여드린 'index명으로 행 삭제'와 동일합니다. 한가지 다른 점은, 조건식에 따라 index명을 선택할 수 있다는 것입니다. 즉, 이 방법을 사용하면 삭제할 index명을 직접 지정하지 않고, 조건문으로 삭제할 행을 선택할 수 있습니다.

아래 예시는 '성별코드'가 1인 행의 index명을 'idx_nm_1'이라는 객체에 저장하고, 이를 'drop()' 함수를 이용하여 삭제하는 경우입니다.

idx_nm_1 = df_sample_4[df_sample_4['성별코드'] == 1].index df_sample_5 = df_sample_4.drop(idx_nm_1)

결과를 보면 '성별코드'가 1인 행은 모두 삭제되고, 2만 남은 것을 알 수 있습니다.

위 예시는 조건문이 하나일 때이고, 조건문이 여러 개 사용될 경우에는 '&(and)''|(or)' 연산자로 조건문을 연결해주면 됩니다. :)

아래 예시에서는, 두 개의 조건문을 '또는'으로 결합하였습니다.

idx_nm_3 = df_sample_4[(df_sample_4['연령대코드(5세단위)'] <= 10) | (df_sample_4['음주여부'] == 1)].index df_sample_7 = df_sample_4.drop(idx_nm_3)

결과를 보면, '연령대코드(5세단위)'는 모두 10 초과이고, '음주여부'는 모두 0임을 확인할 수 있습니다. 위에서 삭제할 행을 '또는'으로 결합했기 때문에, 둘 중 하나라도 만족하는 행은 다 삭제된 것이죠..

DataFrame 행 추가

append, loc, iloc

DataFrame의 행 추가는 'append()'를 사용하는 방법과 'loc[] 또는 iloc[]'를 사용하는 방법이 있습니다. 경우에 따라 둘 중 더 좋은 방법이 있겠지만, 제 개인적인 경험으로 index명을 유지하고 싶다면 'loc[]'를 사용하는게 젤 편했던 거 같습니다.

'append()' 사용하여 행 추가

Dictionary, Series 그리고 DataFrame 과 같은 데이터 구조를 가진 신규 데이터는 모두 기존 DataFrame에 추가할 수 있습니다. 하지만, Dictionary 또는 Series로 된 데이터를 추가할 경우, 추가되는 데이터의 index명을 지정할 수 없고, 오히려 기존 DataFrame의 index가 버려질 수 있습니다.

예를 들면 이런 식입니다.. Dictionary 형태의 'new_data'를 DataFrame 형태의 'df_sample_7'에 추가할 때,

new_data = {'성별코드': '3', '연령대코드(5세단위)' : 10, '허리둘레':100, '흡연상태': 1} df_sample_8 = df_sample_7.append(new_data)

그냥 'append()' 뒤에 넣어주면, 아래와 같이 오류가 발생합니다. 'TypeError' 내용을 살펴보니, Series를 추가하기 위해서는 'ignore_index=True'로 세팅하거나, Series가 이름을 가져야 한다는군요..

그럼 오류가 발생하지 않게 'ignore_index=True' 로 설정해서 데이터를 다시 추가해보겠습니다.

df_sample_8 = df_sample_7.append(new_data, ignore_index=True) df_sample_8.tail()

이번엔 오류 발생없이 마지막 행에 신규 데이터가 추가되었군요.. :) 근데 먼가 이상합니다.. index가 0부터 시작하는 숫자로 바뀌어 버렸습니다. -_- (말 그대로 'index를 ignore' 해버렸군요..)

index명이 큰 의미가 없는 경우에는 문제가 없지만, 지금 예제처럼 index가 가입자를 구분하는 ID라면.. 이런 상황이 난감합니다. 가능하면, index를 유지하면서 데이터를 추가하는 방법이 필요할 것 같군요..

Dictionary나 Series 타입의 데이터가 아니라, DataFrame 타입의 데이터를 추가하는 것은 괜찮은 방법입니다. 아래 예시는 신규 데이터 타입이 DataFrame인 경우, 'append()'로 추가하는 방법입니다.

skp = [(2, 13, 75, 1, 0, 97, 152, 114), (1, 15, 55, 2, 0, 152, 111, 101)] new_data_2 = pd.DataFrame(skp, columns=df_sample_4.columns, index=['SKP099', 'SKP100'])

위에서 만든 'new_data_2'라는 DataFrame을 'df_sample_4'에 추가해보겠습니다.

df_sample_9 = df_sample_4.append(new_data_2) df_sample_9.tail()

추가된 'SKP099''SKP100' 행이 마지막에 있군요. :)

'loc 또는 iloc' 사용하여 행 추가

'loc[]'을 사용할 경우, 새롭게 추가할 데이터의 index명을 [] 안에 넣으면 됩니다. 아래는 'SKP101'이라는 index명으로 데이터를 추가하는 예시입니다.

df_sample_9.loc['SKP101'] = [2, 16, 56, 3, 1, 153, 112, 102] df_sample_9.tail()

결과를 보면, 마지막에 'SKP101'이 추가된 것을 볼 수 있습니다.

'iloc[]'을 사용할 경우에는 [] 안에 추가할 행의 순서를 입력하면 됩니다. 다만, 새롭게 데이터가 들어가면 기존 데이터는 없어지므로(업데이트), 행을 잘못 지정하면 엄한 데이터가 날라갈 수 있습니다. 분명 어떤 경우엔 'iloc[]'를 사용한 행 추가가 유용할 수 있겠지만.... 전 아직 그런 경우를 만나보지 못했습니다. :)

이상입니다. 감사합니다.

Toplist

최신 우편물

태그