DataFrame 특정 값 대체 - DataFrame teugjeong gabs daeche

DataFrame 생성

import pandas as pd

data = {'name':['michael','louis','jack','jasmine'],
        'grades':[90,80,70,60],
        'result':['N/A','N/A','N/A','N/A']}

df = pd.DataFrame(data,columns=['name','grades','result'])

#      name  grades result
#0  michael      90    N/A
#1    louis      80    N/A
#2     jack      70    N/A
#3  jasmine      60    N/A
# grades 값이 90 이라면 result 는 'A'
df.loc[df['grades'] == 90, 'result'] = 'A'

# grades 값이 80 이라면 result 는 'B'
df.loc[df['grades'] == 80, 'result'] = 'B'

# result 값이 'A' 와 'B' 가 아니라면 result 는 'F'
df.loc[(df['result'] != 'A') & (df['result'] != 'B'), 'result'] = 'F'

#      name  grades result
#0  michael      90      A
#1    louis      80      B
#2     jack      70      F
#3  jasmine      60      F

1. 중복된 행 조회 및 삭제

duplicated, drop_duplicates 함수를 이용해보자



이런 데이터가 주어진다고 하자.

nameageblood정국24A진28B태형26O정국24A남준26AB


duplicated() : 중복된 행이 나타나면 True 아니면 False를 나타내는 Boolean 마스크 생성

bts.duplicated()
0  False
1  False
2  False
3  True
4  False

name이 정국인 행과 똑같은 행이 3번째에 또 나와 True값이 나왔다.
그러나 만약 특정 열만 비교해 중복값을 뽑아내고 싶다면 옵션값에 subset을 이용하면 된다.

subset['age']

bts.duplicated(subset=['age'])
0  False
1  False
2  False
3  True
4  True

subset을 사용해 특정 열 'age'만 보고 같은 행이 있는지 Boolean을 통해 알려준다.
여기서 나이만 보기 때문에 24인게 3행에 26인게 4행에 같아 True값이 나왔다.
subset에 여러 열의 값을 넣어 중복된 행을 찾아낼 수도 있다.

subset['age','blood']

bts.duplicated(subset=['age','blood'])
0  False
1  False
2  False
3  True
4  False

위의 결과값에서 알 수 있듯이 나이와 혈액형을 기준으로 중복된 행은 3번째 행인 것을 알 수 있다.
나이가 24, 혈액형이 A이 0행과 3행이 값아 2번째로 같은 값이 나온 3행에서 True값이 나왔다.

drop_duplicates() : 중복된 행들을 제거해주는 함수

bts.drop_duplicates() 

[Output]

nameageblood정국24A진28B태형26O남준26AB


drop_duplicates(['age'], keep = 'first')옵션을 주지 않고 기본 함수를 사용하면 모든 열의 값이 동일한 행을 삭제해준다.
그래서 이름이 전국인 행 전체가 사라진 것을 위와 같이 볼 수 있다.

bts.drop_duplicates(['age'], keep = 'first') 

[Output]

nameageblood정국24A진28B태형26O


2. 데이터프레임에서 특정 열의 특정 값들을 대체

옵션 keep = 'first'를 주면 중복된 값이 처음으로 나오는 행만 남겨두고 삭제하라는 의미이다.
그래서 나이는 26으로 태형, 남준이가 같았지만 처음으로 나온 태형의 행이 남은 것을 알 수 있다.
반대로 keep = 'last'를 주면 마지막에 나온 행이 남을 것이다.

replace, apply 함수를 이용해보자

replace() : Series에 특정값을 다른 값으로

bts['name'] = bts['name'].replace({'진':'슈가'})
bts

[Output]

nameageblood정국24A슈가28B태형26O정국24A남준26AB


또 다른 방법으로는 apply함수를 사용하는 것이다.replace함수를 사용해 name에서 진을 슈가로 값을 대체하고 데이터프레임을 확인해보니 변경되었음을 알 수 있다.

주로 저는 이 방법을 많이 사용하는데 그 이유는 단지 값을 일일이 replace처럼 바꾸는게 아니라 열을 원하는 방향으로 한 번에 변경해주기 때문이다.


예를 들면 age에 3씩 더해주거나 name뒤에 문자열을 추가할 수 있다.

bts['age'] = bts['age'].apply(lambda x : x + 3)

bts['age'] = bts['age'].apply(lambda x : x + 3) 
bts

[Output]

nameageblood정국27A슈가31B태형29O정국27A남준29AB


bts['name'] = bts['name'].apply(lambda x : x + '귀여워')

age가 3씩 증가함을 볼 수 있다.

0  False
1  False
2  False
3  True
4  False
0

[Output]

nameageblood정국 귀여워27A슈가 귀여워31B태형 귀여워29O정국 귀여워27A남준 귀여워29AB


이 밖에서 map, applymap 함수를 사용할 수 있다숫자뿐만 아니라 문자열도 변경하는게 가능하다.
이 밖에도 함수를 다양하게 적용할 수 있고 데이터프레임 열을 같은 형식으로 한 번에 바꾼다는 장점이 있다.

map() : 1차원 원소별 적용하고 리스트로도 반환이 가능

bts['age'].map(lambda x : x+100)

0  False
1  False
2  False
3  True
4  False
1

[Output]

nameageblood정국 귀여워127A슈가 귀여워131B태형 귀여워129O정국 귀여워127A남준 귀여워129AB


apply함수와 같이 age에 100을 더 한 값이 나옴을 볼 수 있다.
다만

apply는 데이터프레임 행별, 열별에 적용이 가능
But, map의 경우 1차원 원소별에만 적용이 가능

applymap() : 2차원 데이터프레임 구조의 원소별 적용

그래서 만약 BTS.applymap(lambda x : x + 100)을 사용하면 데이터프레임 전체에 숫자 100을 더할려고 할 것이다.
그러나 문자열엔 숫자연산이 적용되지 않아 ERROR가 뜬다.
그 점을 유의해면서 applymap함수는 사용해야 한다.

컬럼값을 바꿀 때, for 문으로 바꾸려고 하시는분들이 꽤 계실 것이다.

필자 또한 처음에 for문으로 일일이 바꾸어주었는데, 다른 프로그래밍 언어라면 그렇게 하겠지만, 

파이썬은 진짜 웬만하면 다 만들어놓은게 많다.

(그리고 만들어진 라이브러리들은 C++같은 저레벨언어로 만들어졌기 때문에 실행시간이 훨씬 빠르다.)

판다스를 사용한다 -> 판다스 객체에서 무엇인가 하고싶다 -> 판다스에서 제공할 것이다

이러한 흐름대로 의식을 진행시킨다면, 저처럼 개고생하는 일은 없으실 것이다.


이 포스팅에서는, 아래의 내용을 다룰 것이다.

# Pandas 에서 조건에 맞는 컬럼에서 단일값 바꾸기

# Pandas 에서 조건에 맞는 컬럼에서 여러값 바꾸기


# Pandas 에서 조건에 맞는 컬럼에서 단일값 바꾸기

# 예시 데이터셋

DataFrame 특정 값 대체 - DataFrame teugjeong gabs daeche

dest_loc 컬럼에서 4행의 '대명동'을 '홍대'로 바꾸는 법은 아래와 같다.

## 예시 데이터셋 호출 
df = pd.read_csv("~~~~")

## 단일값 바꾸는 부분 

# 1. Index 기반 접근방법 
df.at[4,'dest_loc'] = '홍대'          # 4행, 'dest_loc'칼럼 값을 홍대로 변경

# 2. True/False 기반 접근 방법
df[(df['dest_loc'] == '대명동')] = '홍대'     # 'dest_loc'칼럼 中 '대명동'과 일치하는 데이터
                                              # '홍대'로 일괄변경(만족하는 값이 하나일경우 단일값 변경)
                                                    

# Pandas 에서 조건에 맞는 컬럼에서 여러값 바꾸기

# 예시 데이터셋

DataFrame 특정 값 대체 - DataFrame teugjeong gabs daeche

이번에는,

dest_loc과 boarding_loc에 괄호<(,)> 를 포함한 값을 모두

괄호안의 값으로 변경하는 법이다.

# 아래 코드는 추천하지 않는 형식의 코드(For문)이다

(제가 삽질했던 코드이다.. ㅠㅠㅠ)

240만건 기준 대충 10분(수행시간)은 걸렸던것 같다...

# 1. True/False 기반 For 문 접근 방법 (비추천)

# 주의 : 이런 짓 제발 하지말자
# 연산속도 엄청느림 + CopyWarning 발생 (되긴함)


df['dest_loc']=df['dest_loc'].fillna('None')

# cleaning dest_loc
idx= 0
for loc in df['dest_loc'] :
  if (loc.find('(') != -1) :
    clean_addr = loc.split('(')[1].replace(')',"")
    df['dest_loc'][idx]=clean_addr

  idx += 1

# 아래는 판다스에서 제공하는 apply 메소드를 이용한 매우 강추하는 방법이다

(연산속도가 말도안되게 빠르다...)

240만건 기준 1분(수행속도)도 안걸린것 같다... ㅠㅠ

공백까지 지우려면 위의 방법으로는 연산속도가 더 증가하게되는데,

apply로 아주 간단히... 가능하다 ㅠㅠ

# 2. Pandas apply 메소드 기반 접근방법 (강추!)

# 연산속도 엄청빠름

def cleaning(x) :
  if str(x).find("(") != -1 :
    return str(x).split("(")[1].replace(")","") 
  return str(x)


# apply메소드의 lambda 함수는 공백까지 지우기 위해 사용한 코드입니다.
# 이렇게 중복으로도  사용가능하다는걸 알려드리고 싶었네요 ㅎ.ㅎ

# boarding_loc cleaning
df['boarding_loc']=df['boarding_loc'].fillna("NONE")
df['boarding_loc']=df['boarding_loc'].apply(cleaning).apply(lambda x:x.replace(" ",""))

# dest_loc cleaning
df['dest_loc']=df['dest_loc'].fillna("NONE")
df['dest_loc']=df['dest_loc'].apply(cleaning).apply(lambda x:x.replace(" ",""))