본문 바로가기

Data analysis/실습 & 프로젝트

[파이썬 데이터 분석 실무 테크닉 100] 1-2. 대리점 데이터를 가공하는 테크닉 10

728x90
반응형

책 정보 : https://book.naver.com/bookdb/book_detail.nhn?bid=16427881 

 

파이썬 데이터 분석 실무 테크닉 100

《파이썬 데이터 분석 실무 테크닉 100》은 실제 비즈니스 현장에서 마주칠 수 있는 100개의 예제를 풀면서 현장 분위기를 몸에 익히고 현장에 맞게 기술을 응용하는 힘을 기를 수 있게 설계한 문

book.naver.com


[데이터 정보]

  • uriage.csv : 매출 이력, 기간은 2019년 1월~2019년 7월
  • kokyaku_daicho.xlsx : 대리점에서 관리하는 고객 정보

 

1. 데이터 읽어들이기

import pandas as pd
uriage_data = pd.read_csv("C:/data/2장/uriage.csv")
uriage_data.head()

uriage_data  (매출 이력)

  • item_name이나 item_price에 결측치나 오류가 보임
  • 이처럼 데이터에 나타나는 입력 오류나 표기 방법의 차이가 부정합을 일으킬 때 '데이터의 정합성에 문제가 있다'
kokyaku_data = pd.read_excel("C:/data/2장/kokyaku_daicho.xlsx")
kokyaku_data.head()

kokyaku_data (고객 정보)

 

  • 정합성을 갖추기 위해서는 데이터의 속성이나 의미를 이해해야 함
  • 정합성 확보는 우선 데이터의 오류를 파악하는 것부터 시작

 

2. 데이터의 오류를 살펴보기

uriage_data["item_name"].head()

 

uriage_data["item_price"].head()

 

3. 데이터에 오류가 있는 상태로 집계하기

uriage_data["purchase_date"] = pd.to_datetime(uriage_data["purchase_date"]) # datetime형으로 변환
uriage_data["purchase_month"] = uriage_data["purchase_date"].dt.strftime("%Y%m") # 날짜를 연월 형태로 변환
# 세로축에 구입 연월, 가로축에 상품의 건수로 집계
res = uriage_data.pivot_table(index="purchase_month", columns="item_name", aggfunc="size", fill_value=0)
res

데이터 수정 전 집계 결과 (금액)

  • '상품S'나 '상품s'처럼 원래 동일한 상품이 다른 상품으로 집계된 것을 확인할 수 있음 -> 원래 26개의 상품이 99개의 상품으로 늘어남
  • 결측치(NaN) 포함 O -> size 함수 / 결측치(NaN) 포함 X -> count 함수

 

4. 상품명 오류 수정하기

현재 상태 파악하기

print(len(pd.unique(uriage_data.item_name))) # 상품명의 유니크 수(중복 제외) 확인

99 -> 원래 A~Z까지 26개의 상품이 99개로 늘어남

 

대문자로 변경 → 공백 제거 → 오름차순으로 정렬

uriage_data["item_name"] = uriage_data["item_name"].str.upper() # 상품명에 있는 소문자를 대문자로 변환
uriage_data["item_name"] = uriage_data["item_name"].str.replace(" ", "") # 공백 제거
uriage_data["item_name"] = uriage_data["item_name"].str.replace("  ", "") # 공백 제거
uriage_data.sort_values(by=["item_name"], ascending=True) # item_name 순으로 정렬

 

결과 검증 (상품명과 개수 가져오기)

print(pd.unique(uriage_data["item_name"]))
print(len(pd.unique(uriage_data.item_name)))

상품 개수가 26개로 올바르게 나옴

 

5. 금액의 결측치를 수정하기

 

우선, 데이터에 결측치가 있는지 확인하기

uriage_data.isnull().any(axis=0) # axis=0이면 행방향, axis=1이면 열방향

결측치가 있음을 알 수 있음

 

df.loc[조건, 조건과 일치하는 데이터 중에서 어떤 칼럼을 가져올지 결정] -> 조건에 일치하는 데이터를 추출

flg_is_null = uriage_data["item_price"].isnull() # item_price 중에 결측치가 있는 곳을 조사
uriage_data.loc[flg_is_null, "item_name"].unique()

결측치가 있는 상품명 리스트

 

  • trg -> 위에서 구한 결측치가 있는 상품명 리스트들
  • 같은 상품의 단가를 이용하여 결측치를 채우기
  • price -> '결측치가 있는 상품'과 같은 상품이며 금액이 올바르게 입력된 행을 loc로 찾아 그 그액을 가져오기
  • 결측치가 있는 데이터를 추출하고, 앞에서 가져온 금액 데이터 price를 결측치에 대입
for trg in list(uriage_data.loc[flg_is_null, "item_name"].unique()): # list()로 변수의 값을 리스트 형식으로 변환
    # 결손치가 있는 상품과 같은 상품의 다른 데이터에서 금액을 가져올 수 있음
    price = uriage_data.loc[(~flg_is_null) & (uriage_data["item_name"] == trg), "item_price"].max()
    # 가져온 금액으로 데이터를 수정 -> 결측치가 있는 데이터를 추출하고, 앞에서 가져온 금액 데이터 price를 결측치에 대입
    uriage_data["item_price"].loc[(flg_is_null) & (uriage_data["item_name"] == trg)] = price
    
uriage_data.head()

결측치가 없어짐

검증하기

uriage_data.isnull().any(axis=0)

 

각 상품의 금액이 정상적으로 수정됐는지 확인하기

for trg in list(uriage_data["item_name"].sort_values().uniqueque()):
    print(trg + "의 최고가 : " + str(uriage_data.loc[uriage_data["item_name"] == trg]["item_price"].max()) +
         "의 최저가 : " + str(uriage_data.loc[uriage_data["item_name"] == trg]["item_price"].min(skipna=False)))

  • 모든 상품의 최대 금액과 최소 금액이 일치하는 것으로 봐서 성공적으로 금액을 수정했다는 것을 알 수 있음
  • skipna=False에서 skipna는 NaN의 무시 여부를 설정

 

6. 고객 이름의 오류 수정하기

kokyaku_data["고객이름"].head() # 고객 정보의 고객 이름

공백 존재

uriage_data["customer_name"].head() # 매출 이력의 고객 이름

 

고객 정보의 고객 이름에서 공백을 제거하기

kokyaku_data["고객이름"] = kokyaku_data["고객이름"].str.replace("  ", "")
kokyaku_data["고객이름"] = kokyaku_data["고객이름"].str.replace(" ", "")
kokyaku_data["고객이름"].head() # 수정 후 고객 정보의 고객 이름

공백 없어짐

 

7. 날짜 오류 수정하기

kokyaku_data["등록일"].head()

  • 여러 가지 서식의 날짜가 있는 것을 확인할 수 있음
  • 동일한 포맷으로 통일해야 함

 

  • 고객 정보의 등록일이 숫자인지 아닌지를 판정
  • 등록일이 object지만 문자열(str)로 바꾼 후에 적용해야 함
  • str.isdigit() : 문자열이 숫자인지 아닌지를 True, False로 리턴
flg_is_serial = kokyaku_data["등록일"].astype("str").str.isdigit()
# flg_is_serial
flg_is_serial.sum() # 숫자로만 된 등록일의 개수 -> 22

 

  • 숫자로 등록된 부분을 수정
  • to_timedelta() : 숫자를 날짜로 변환, unit="D" -> '~일'로 바꾸기
  • loc()을 이용 -> flg_is_serial 조건으로 데이터를 추출하고 날짜로 변경
fromSerial = pd.to_timedelta(kokyaku_data.loc[flg_is_serial, "등록일"].astype("float"), unit="D") + pd.to_datetime("1900/01/01")
fromSerial # 숫자를 날짜로 변경

 

날짜로 변환된 데이터로 서식을 통일 (2018/01/4와 같이 슬래시로 구분된 서식을 하이픈으로 구분된 서식으로 통일)

fromString = pd.to_datetime(kokyaku_data.loc[~flg_is_serial, "등록일"])
fromString

 

숫자를 날짜로 수정한 데이터와 서식을 변경한 데이터를 결합해서 데이터를 갱신

kokyaku_data["등록일"] = pd.concat([fromSerial, fromString])
kokyaku_data

 

등록일로부터 등록월을 추출하여 집계하기

kokyaku_data["등록연월"] = kokyaku_data["등록일"].dt.strftime("%Y%m")
rslt = kokyaku_data.groupby("등록연월").count()["고객이름"]
print(rslt)
print(len(kokyaku_data))

 

등록된 칼럼에 숫자 데이터가 남아 있는지를 확인

flg_is_serial = kokyaku_data["등록일"].astype("str").str.isdigit()
flg_is_serial.sum() # 0 -> 모든 숫자 데이터가 날짜로 수정된 것을 확인

 

8. 고객 이름을 키로 두 개의 데이터를 결합(조인)하기

 

uriage_data를 기준으로 kokyaku_data를 결합

join_data = pd.merge(uriage_data, kokyaku_data, left_on="customer_name", right_on="고객이름", how="left")
join_data = join_data.drop("customer_name", axis=1) # 열(column)방향으로 해당 컬럼 제거 (중복이므로)
join_data

 

9. 정제한 데이터를 덤프하기

: 깨끗해진 데이터를 파일로 출력(더프)해두고, 분석할 때 출력한 파일을 다시 읽어 들이면 데이터 정제를 다시 할 필요가 없음

 

컬럼의 배치 조정 -> purchase_data와 purchase_month는 가까이 있는 편이 다루기 편함

dump_data = join_data[["purchase_date", "purchase_month", "item_name", "item_price", "고객이름", "지역", "등록일"]]
dump_data

 

  • 수정한 dump_data를 to_csv()를 이용해서 파일로 출력하기
  • 실행하면 같은 폴더에 dump_data.csv가 출력되는 것을 확인할 수 있음
dump_data.to_csv("dump_data.csv", index=False)

 

10. 데이터 집계하기

import_data = pd.read_csv("dump_data.csv")
import_data

 

purchase_month를 세로축으로 해서 상품별로 집계하기

byItem = import_data.pivot_table(index="purchase_month", columns="item_name", aggfunc="size", fill_value=0)
byItem

 

purchase_month를 세로축으로 지정하고 매출 금액 집계하기

byPrice = import_data.pivot_table(index="purchase_month", columns="item_name", values="item_price", aggfunc="sum", fill_value=0)
byPrice

 

purchase_month를 세로축으로 지정하고 고객 집계하기

byCustomer = import_data.pivot_table(index="purchase_month", columns="고객이름", aggfunc="size", fill_value=0)
byCustomer

 

purchase_month를 세로축으로 지정하고 지역 집계하기

byRegion = import_data.pivot_table(index="purchase_month", columns="지역", aggfunc="size", fill_value=0)
byRegion

 

집계 기간에 구매 이력이 없는 사용자 확인하기 -> 고객 대상을 기준으로 매출 이력을 오른쪽 조인해서 결합하기

away_data = pd.merge(uriage_data, kokyaku_data, left_on="customer_name", right_on="고객이름", how="right")
away_data[away_data["purchase_date"].isnull()][["고객이름", "등록일"]]

 

 

728x90
반응형