이용할 데이터 정보
011.데이터를 읽어 들이자
1
2
3
4
5
6
7
8
| import pandas as pd
uriage_data = pd.read_csv("uriage.csv")
# uriage: 매출 이력
uriage_data.head()
kokyaku_data = pd.read_excel("kokyaku_daicho.xlsx")
# kokyaku: 고객 정보
kokyaku_data.head()
|
❗입력 오류나 표기 방법의 차이가 부정합을 일으킬 때 “데이터의 정합성에 문제가 있다”라고 합니다.
데이터 오류의 에
❗정합성 확보는 우선 데이터의 오류를 파악하는 것부터 시작한다.
012.데이터의 오류를 살펴보자
1
| uriage_data["item_name"].head()
|
❗ 이대로 분석하면 상품A, 상 품 a, 상품a가 모두 다른 상품으로 인식!
1
| uriage_data["item_price"].head()
|
❗결측치 존재
013.데이터에 오류가 있는 상태로 집계해 보자
1
2
3
4
5
| uriage_data["purchase_date"] = pd.to_datetime(uriage_data["purchase_date"])
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)
# size = 집계 단위
res
|
1
2
| res = uriage_data.pivot_table(index="purchase_month", columns="item_name",values="item_price", aggfunc="sum", fill_value=0)
res
|
- 문제점: 동일한 상품이 다르게 집계되어 상품의 갯수가 26개 -> 99개
014.상품명 오류를 수정하자
1
2
3
4
5
6
7
8
9
10
| # 현재 상태 파악(개선되었는지 확인 위해)
print(len(pd.unique(uriage_data.item_name)))
# 99
# unique: 중복을 제외한 데이터 건수 확인
# 데이터의 오류 수정
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)
|
1
2
3
4
5
| # 결과 검증
print(len(pd.unique(uriage_data["item_name"])))
print(pd.unique(uriage_data["item_name"]))
# 26
# ['상품A' '상품S' '상품Z' '상품V' '상품O' '상품U' '상품L' '상품C' '상품I' '상품R' '상품X' '상품G''상품P' '상품Q' '상품Y' '상품N' '상품W' '상품E' '상품K' '상품B' '상품F' '상품D' '상품M' '상품H''상품T' '상품J']
|
015.금액의 결측치를 수정하라
1
| uriage_data.isnull().any(axis=0)
|
집계 기간에 상품 단가의 변동이 없다는 전제조건이 있었기 때문에 같은 상품의 단가를 이용하면 수정할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
| flg_is_null = uriage_data["item_price"].isnull()
# 결측치 있는 곳 조사
# 어떤 행에 결측치가 있는지 False, True로 표시
for trg in list(uriage_data.loc[flg_is_null, "item_name"].unique()):
# 결측치가 있는 상품명 리스트 작성
# list는 변수의 값을 리스트 형식으로 변환
# loc: 조건에 맞는 데이터 추출 -> [조건, 데이터 가져올 칼럼]
# unique: 추출한 상품명에서 중복을 제거
price = uriage_data.loc[(~flg_is_null)&(uriage_data["item_name"] == trg), "item_price"].max()
# "결측치가 있는 상품"과 같은 상품이며 금액이 올바르게 입력된 행을 찾고 그 금액을 가져옴.
uriage_data["item_price"].loc[(flg_is_null) & (uriage_data["item_name"]==trg)] = price
uriage_data.head()
|
1
2
| # 검증
uriage_data.isnull().any(axis=0)
|
1
2
3
4
| #각 상품의 금액이 정상적으로 수정됐는지 확인
for trg in list(uriage_data["item_name"].sort_values().unique()):
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: NAN의 무시 여부 결정. false일때는 NaN이 존재할 경우 최솟값이 NaN으로 표시됨.
|
016.고객 이름의 오류를 수정하자
1
2
| kokyaku_data["고객이름"].head()
# 고객 이름
|
1
2
| 
# 매출 이력의 고객 이름
|
❗고객 이름들의 형식이 일정하지 않음
1
2
3
4
| # 수정
kokyaku_data["고객이름"] = kokyaku_data["고객이름"].str.replace(" ", "")
kokyaku_data["고객이름"] = kokyaku_data["고객이름"].str.replace(" ", "")
kokyaku_data["고객이름"].head()
|
❗같은 이름이 존재한다면 등록일, 생년월일 등 다른 정보를 이용해 구분해야 한다.
017.날짜 오류를 수정하자
문제 확인
❗날짜 형식이 다르다!
1
2
3
4
5
6
7
| # 숫자로 읽히는 데이터 확인(ex.42782)
flg_is_serial = kokyaku_data["등록일"].astype("str").str.isdigit()
flg_is_serial.sum()
# 22
# str.isdigit(): 숫자인지 아닌지 판단
# 판단결과 숫자로 된 장소를 flg_is_serial에 저장
|
문제 수정
1
2
3
4
5
| # 숫자로 등록된 부분 수정
fromSerial = pd.to_timedelta(kokyaku_data.loc[flg_is_serial, "등록일"].astype("float"), unit = "D") + pd.to_datetime("1900/01/01")
# timedelta: 숫자를 날짜로 변경
# unit = "D": 활용해 숫자 데이터를 ‘~일’ 데이터로 바꿔줌.
fromSerial
|
1
2
| fromString = pd.to_datetime(kokyaku_data.loc[~flg_is_serial,"등록일"])
fromString
|
1
2
3
| # 데이터 갱신
kokyaku_data["등록일"]=pd.concat([fromSerial, fromString])
kokyaku_data
|
확인
1
2
3
4
5
6
| # 등록일로부터 등록월을 추출해서 집계
kokyaku_data["등록연월"] = kokyaku_data["등록일"].dt.strftime("%Y%m")
rslt = kokyaku_data.groupby("등록연월").count()["고객이름"]
print(rslt)
print(len(kokyaku_data))
# 200
|
1
2
3
4
| # 숫자 항목 유무
flg_is_serial = kokyaku_data["등록일"].astype("str").str.isdigit()
flg_is_serial.sum()
# 0
|
018.고객 이름을 키로 두 개의 데이터를 결합(조인)하자
❗1장에서는 정합성이 있는 데이터였기에 공통키로 결합할 수 있었지만, 여기서는 두 개의 데이터의 서로 다른 열을 지정해서 결합해야 한다.
❗이 과정을 데이터 정제라고 한다.
1
2
3
4
5
| join_data = pd.merge(uriage_data, kokyaku_data, left_on="customer_name", right_on="고객이름", how="left")
# left_on, right_on으로 결합할 데이터를 지정
join_data = join_data.drop("customer_name", axis=1)
# 왜 customer_name을 기준으로 합쳤는데 customer_name을 삭제? 공통된게 없으면 확인할 수 없으니 매출 데이터에서 아예 삭제한다는 느낌...
join_data
|
019.정제한 데이터를 덤프(파일로 출력)하자
❗칼럼 위치를 직관적으로 이해하기에 좋게 조정하자!
1
2
3
4
| dump_data = join_data[["purchase_date","purchase_month", "item_name", "item_price", "고객이름", "지역", "등록일"]]
dump_data
dump_data.to_csv("dump_data.csv", index = False)
|
020.데이터를 집계하자
데이터 불러오기
1
2
| import_data = pd.read_csv("dump_data.csv")
import_data
|
상품별 집계
1
2
| byItem = import_data.pivot_table(index="purchase_month", columns="item_name", aggfunc="size", fill_value=0)
byItem
|
매출 금액, 고객, 지역 집계
1
2
| byPrice = import_data.pivot_table(index="purchase_month", columns="item_name",values="item_price", aggfunc="sum", fill_value=0)
byPrice
|
1
2
| byCustomer = import_data.pivot_table(index="purchase_month", columns="고객이름", aggfunc="size", fill_value=0)
byCustomer
|
1
2
| byRegion = import_data.pivot_table(index="purchase_month", columns="지역", aggfunc="size", fill_value=0)
byRegion
|
집계 기간에 구매 이력이 없는 사용자 확인
1
2
| away_data = pd.merge(uriage_data, kokyaku_data, left_on = "customer_name", right_on="고객이름", how="right")
away_data[away_data["purchase_date"].isnull()][["고객이름", "등록일"]]
|