Data preprocessing

[데이터 전처리#3] 데이터 구조 전처리 - 집약

j.d 2023. 7. 4. 13:03

지난 포스팅에서 데이터 구조 전처리 중 추출에 대해 알아보았습니다.

 

열 추출, 행 추출에 관한 내용이었습니다.

 

[데이터 전처리#2] 데이터 구조 전처리 - 추출

지난 시간 데이터 전처리의 전체적인 개요에 대해 설명드렸습니다. [데이터 전처리#1] 데이터 전처리 개요 최근 인터넷과 전자 기기들의 발달로 매일 엄청난 양의 데이터가 생성되고 있습니다.

just-data.tistory.com

이번 시간에는 데이터 구조 전처리 중 집약에 대한 내용입니다.


집약

예를 들어 시험 과목별로 점수의 평균값을 계산하면 시험 과목의 난이도를, 각 학생이 받은 점수의 평균값을 계산하면 학생별 결과를 쉽게 파악할 수 있습니다.

 

이렇게 데이터의 가치를 되도록 손실 없이 압축하여 데이터의 단위(데이터 행의 의미)를 변환할 수 있도록 하는 처리집약이라고 합니다.

집약 처리는 사람과 시스템 모두에게 의미가 있습니다.

 

사람에게는 데이터의 전체적인 경향을 파악하는데 도움을 줍니다. 

 

또한 시스템에게는 정보 손실이 적은 변환 처리가 가능해지므로 유익하다고 할 수 있습니다.

 

데이터와 종류의 개수 산출

가장 기본적인 집약 처리로 데이터 카운트(집계)가 있습니다.

 

일반적을 대상 데이터 행 수를 세는 작업입니다.

 

또 데이터 값의 종류를 카운팅 하는 유니크 카운트도 존재합니다.

 

둘다 나타내는 파이썬 코드입니다.

result = df.groupby("hotel_id").agg({'reserve_id':"count", "customer_id": "nunique"})

result.reset_index(inplace = True)
result.columns = ["hotel_id", "rsv_cnt", "cus_cnt"]
result.head()

 

합계값 계산

월별 매출처럼 데이터의 합을 계산해야 하는 경우가 존재합니다.

 

합계 처리는 수치 데이터를 대상으로 하는 집약 처리 중 가장 단순하며 유용합니다.

result = df.groupby(["hotel_id", "people_num"])["total_price"].sum().reset_index() # 집약 처리가 하나라면 agg 함수를 사용하지 않는 것이 간결하다.
result.rename(columns = {"total_price": "price_sum"}, inplace = True) # 변경할 열 이름이 적다면 rename을 사용하는 편이 좋다.
result.head()

 

분포계산

분산과 표준편차는 데이터의 분포 정도를 나타냅니다. 

result = df.groupby("hotel_id").agg({"total_price": ["var", "std"]}).reset_index()
result.columns = ["hotel_id", "price_var", "price_std"]
result.fillna(0, inplace = True) # 데이터가 한 건이면, 분산값과 표준편찻값이 NA가 되므로 0으로 변환한다.
result.head()

 

최댓값, 최솟값, 대푯값 산출

평균만을 그대로 받아들이면 결과를 잘못 인식할 수 있습니다.

 

왜냐하면 평균값이 같아도 데이터 분포가 다르면 데이터의 특성은 크게 달라지기 때문입니다.

 

따라서 평균값 외에도 다양한 지표를 사용해야 합니다.

※ 중앙값이나 백분위수를 계산하려면 정렬을 해야 하기 때문에 메모리와 시간이 많이 소모됩니다.

result = df.groupby("hotel_id").agg({"total_price": ["max", "min", "mean", "median", lambda x: np.percentile(x, q = 20)]}).reset_index() # agg 함수에서는 백분위 값의 집계처리를 문자열로 지정할 수 없다.
result.columns = ["hotel_id", "price_max", "price_min", "price_mean", "price_median", "price_20per"]
result.head()

df.describe()

 

최빈값 계산

범주형에도 최빈값이라는 형태로 대표값이 존재합니다.

 

수치 데이터도 범주형으로 변환하여 최빈값을 구할 수 있습니다.

df["total_price"].round(-3).mode()

 

순위 계산

전처리 과정 중 순위를 계산해야 하는 일이 종종 생깁니다.

 

대상 데이터를 추리거나 복잡한 시간 데이터를 결합할 때 시간 순서로 순위를 매겨서 결합의 조건으로도 이용할 수 있습니다.

 

순위를 정하려면 정렬을 해야 하는데 위에서 언급했던 것처럼 정렬을 하게 되면 계산 비용이 증가하게 됩니다.

 

하지만 순위를 매기는 범위를 나누는 처리 등으로 계산 비용을 줄일 수 있습니다. 

 

아래의 표처럼 순위를 매기는 여러 함수가 존재합니다. 

  • min_rank/min/RANK: 같은 값의 순위 2~5위를 최소인 2위로 측정
  • max: 같은 값의 순위 2~5위를 최대인 5위로 측정
  • row_number/first/ROW_NUMBER: 같은 값의 순위 2~5위에서 먼저 읽힌 순서대로 순위를 측정
  • last:같은 값의 순위 2~5위에서 맨 마지막에 읽힌 순서대로 순위 측정
  • random: 같은 값의 순위 2~5위에서 랜덤 하게 순위를 매긴다.
  • average: 같은 값의 순위 2~5위의 평균값인 3.5로 순위를 매긴다.
  • dense_rank: 같은 값의 순위 2~5위를 최소 순위인 2위로 매기고 다음 순위를 3위로 매긴다.

시간 데이터에 번호 부여

고객별 예약 시간에 따른 순위를 매겨보도록 하겠습니다.

df["reserve_datetime"] = pd.to_datetime(df["reserve_datetime"], format = "%Y-%m-%d %H:%M:%S") # rank 함수는 수치형 데이터만 다루므로 문자열에서 timestamp 형으로 변환

df["log_no"] = df.groupby("customer_id")["reserve_datetime"].rank(ascending = True, method = "first")
df.head()

랭킹

호텔별 예약 건수에 따른 순위를 매겨보도록 하겠습니다.

 

먼저 호텔별로 예약 건수를 계산한 후 순위를 매겨야 합니다.

reserve_df = df.groupby("hotel_id").size().reset_index()
reserve_df.columns = ["hotel_id", "rsv_cnt"]

reserve_df["rsv_cnt_rank"] = reserve_df["rsv_cnt"].rank(ascending = True, method = "min")
reserve_df.drop("rsv_cnt", axis = 1, inplace = True)
reserve_df.head()


이번 시간에는 groupby를 이용해 여러 가지 집약 처리에 대해 알아보았습니다.

 

파이썬을 자주 사용했다면 크게 어려운 부분 없이 이해하셨을 거라 생각됩니다.

 

포스팅 내용 중  다른 생각이 있는 분 혹은 수정해야 할 부분이 있으시면 댓글을 통해 그 의견을 나눠보면 너무 좋을 것 같습니다.

 

 본 포스팅의 내용은 데이터 전처리 대전을 참고하였습니다.