[Pandas] 데이터프레임 다루기 개고수가 되어보기 ㄷㄷ;

seulzzang·2023년 1월 18일
0


제목만 거창하지 사실 프로젝트 할 때 사용한 데이터프레임 다루는 방법들에 대해 정리하는 글이다.
나의 프로젝트 기반 코드이기 때문에 가독성은 현저히 떨어질 것이다.. 기본형(?)으로 제공되는 코드가 아니니 본인의 입맛따라 필요한 것만 골라 사용하시면 될듯 하다.

1. 특정 컬럼을 인덱스로 지정하고 싶을 때

df = df.set_index('Date')

set_index를 사용해 주면 된다. 괄호에는 인덱스로 사용할 컬럼의 이름을 넣어주면 됨.
(내가 프로젝트에서 이 메서드를 이용한 이유는, 모델링할 때 날짜가 인덱스가 됐으면 좋겠어서 였는데, 날짜가 스트링 타입이여서 이를 데이트타임 타입으로 바꾸는 과정도 거쳤었다.)

df['Date'] = pd.to_datetime(df['Date'])
df = df.set_index('Date')

이런 코드를 되게 자주 썼다.

2. 데이터프레임 merge를 여러개 하고 싶을 때

from functools import reduce

df_list = [actual_average_price, forecast_index, trading_volume, total_house, average_jeonse, ratio, purchase_power, actual_price, change_rate, monthly_conversion, selling_price, unsold]
df_merge = reduce(lambda left, right: pd.merge(left, right, on=['Date', 'District'], how='outer'), df_list)
df_merge = df_merge.drop(columns=['ID_x', 'ID_y'], axis=1)

두번째줄에서 merge에 on은 합치고 싶은 기준 컬럼들이다.
(merge에 대한 설명은 기타 여러 블로그에 많으니 구글링 추천..)

우리의 데이터프레임은 기본적으로 날짜, 자치구, 기본키인 ID가 포함된 데이터프레임이었는데, 날짜, 자치구를 기준으로 merge를 하게 되면 ID_x, ID_y등이 생기는 것들 때문에 drop도 진행해줬다.

이렇게 진행하면 전체 기간 중 없는 값들은 자동으로 NaN값을 채워주니 걱정 안해도 된다! 다만 이걸 사용하면 warning이 뜨는데

FutureWarning: Passing 'suffixes' which cause duplicate columns {'ID_x'} in the result is deprecated and will raise a MergeError in a future version.
  df_merge = reduce(lambda left, right: pd.merge(left, right, on=['Date', 'District'], how='outer'), df_list)

..뭐 대충 이런 내용.
중복 열을 전달하는 ID_x같은 것들이 더이상 전달되지 않아서 향후 버전에서는 머지에러를 발생할 수 있다는 경고이다.
급할 때 참고만 하시길

3. 특정 조건을 만족하는 행 별로 데이터 프레임을 만들고 기타 등등의 작업 하기

제목을 어떻게 지어야 할까.. 하다가 나의 어휘력에는 이게 한계라 그냥 이대로 적었다..
우리가 하는 프로젝트에선 서울 25개의 자치구별로 뭔가를 뚱땅뚱땅하는게 많았는데 그래서 데이터프레임을 쪼갰다가 합쳤다가 뭘했다가 버렸다가 이런 작업들이 상당히 많았다.
그래서 우리가 사용한 코드를 예시로 들자면

gu_list = ['강남구', '강동구', '강북구', '강서구', '관악구', '광진구', '구로구', '금천구', '노원구', '도봉구', '동대문구', '동작구', '마포구', '서대문구', '서초구', '성동구', '성북구', '송파구', '양천구', '영등포구', '용산구', '은평구', '종로구', '중구', '중랑구']

def make_district_df(df: pd.DataFrame, district_name: str):
  new_df = df[df['District'] == district_name]
  return new_df
 
 df_list = []

for gu in gu_list:
  df = make_district_df(data, gu)
  # 각 자치구별 컬럼의 평균값으로 결측치를 채운다
  df[used_features] = df[used_features].fillna(round(df[used_features].mean(), 1))
  # df = df.fillna(round(df.mean(), 1))

  df_list.append(df)
  1. make_district_df의 함수는 특정 자치구 이름으로 된 데이터프레임만 추출하는 함수이다. 사용할 데이터프레임 안에 어떤 조건을 넣어주면(나의 코드에선, District컬럼이 district_name인, 예를 들어 District컬럼이 종로구라는 값을 가진 부분만 추출하는 것이다) 해당 자치구 DF만 생성해준다.
  2. for문에서는 각 자치구별로 데이터프레임을 쪼갠 뒤, 평균값으로 결측치를 채우거나 중앙값 대체법을 사용하거나.. 기타등등 각 자치구별로 진행해줘야 할 작업을 거친 뒤 다시 합쳐주는 과정이다.

이렇게 하면 df_list가 약간 이중 리스트 형식으로 출력이 되는데

new_data = pd.concat(df_list, axis=0)

concat을 이용하여 axis=0으로 두면 행 별로 다 이어 붙여준다 ^_^

4. loc과 iloc 활용하기

나는 loc이 명시적 인덱싱이고 iloc이 묵시적인덱싱이라는 말을 들었을때 정말 와닿지 않았다.. 그래서 맨날 헷갈려서 iloc이 뭐고 loc이 뭔지 인덱싱 할 때 어떤 값을 넣어줘야 하는지 헷갈렸는데 내가 외운 방법은 iloc -> int, index location (숫자값만 넣어줘야함. 정말 내가 보고싶은 행이 몇 번째인지를 넣어줘야 함)이렇게 생각하니까 편하더라 ㅎㅎ

4-1. loc으로 특정 값 지정해주기

temp.loc['2022-11-01', 'PredictPrice'] = price

이런식으로 사용하면 된다.
앞서 나는 Date를 인덱스로 사용하는데, 11월 1일 인덱스를 가지는 PredicePrice컬럼을 가리키는 코드이다.
이렇게 해서 price를 할당해줄 수 있다.

4-2. iloc 사용하기

위에서 말했다시피 iloc을 사용할 땐 숫자만 사용해야한다. loc에 사용하듯이 컬럼의 이름을 넣거나, 행의 번호가 아닌 어떤 특정 인덱스 값을 넣으면 오류가 난다.

X_features = onehot.iloc[:, :-2]
y_target = onehot.iloc[:, -1]

보통 이런식으로 사용했다. 콤마 이전을 행, 콤마 이후를 열(컬럼)으로 생각하면 된다. :(콜론)을 사용하면 행 전체를 가르키고, 이후에 :-2라면 뒤에서 두번째 값 부터 맨 앞 까지, -1이라면 맨 마지막 열만 가르키는 것! 보통 파이썬에서 인덱싱 할 때 처럼 똑같이 하면된다. (당연하다 판다스는 파이썬의 라이브러리니께)
iloc을 사용하고 특정 컬럼의 이름을 넣어서 인덱싱을 하고 싶으면

df.iloc[:]['PredictPrice']

이런식으로 하면 시리즈를 반환받을 수 있다.
아.. 근데 똑같이 데이터프레임 형식으로 보고싶다고ㅠㅠ 라면

df.iloc[:][['PredictPrice']]

컬럼명에 대괄호 한쌍만 더 씌워주면 된다.

나만 몰랐던 꿀팁같은 꿀팁..🍯

위에 말했던 것 처럼 아니 나는 똑같이 데이터프레임으로 보고싶은데 자꾸 시리즈가 반환돼서 짜증났다면 컬럼에 대괄호 한쌍만 더 씌워주면 됨 ㅎ;;


일단은 이정도로 마무리를 하겠다..!! 전처리를 하면서 사용했던 코드는 이정도 인 것 같다. 아주 기본적인 columns, info, describe.. 기타등등의 메서드들은 적지 않았다. 인덱싱을 하거나 어떤 특정 부분만 데이터프레임으로 따로 보고 싶을 때 기억이 잘 안나서 매번 구글링 하게 되는.. 귀찮지만 알아두면 편한 것들을 내 나름대로 정리해 보았다.
다음은 모델링 부분을 정리하고자 한다.

profile
중요한 것은 꺾이지 않는 마음

0개의 댓글