본문 바로가기
데이터 분석

가상 쇼핑몰 데이터 예제

by 코낄2 2023. 12. 16.
import pandas as pd
retail = pd.read_csv('/content/drive/MyDrive/KDT/데이터분석/데이터/OnlineRetail.csv')

# 출력 row 갯수 설정
pd.options.display.max_rows = 6
=> 컬럼이 6개만 표출됨
  • .info() : 정보 보기
retail.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 541909 entries, 0 to 541908
Data columns (total 8 columns):
 #   Column       Non-Null Count   Dtype  
---  ------       --------------   -----  
 0   InvoiceNo    541909 non-null  object 
 1   StockCode    541909 non-null  object 
 2   Description  540455 non-null  object 
 3   Quantity     541909 non-null  int64  
 4   InvoiceDate  541909 non-null  object 
 5   UnitPrice    541909 non-null  float64
 6   CustomerID   406829 non-null  float64
 7   Country      541909 non-null  object 
dtypes: float64(2), int64(1), object(5)
memory usage: 33.1+ MB
  • InvoiceNo: 주문 번호
  • StockCode: 상품 코드
  • Description: 상품 설명
  • Quantity: 주문 수량
  • InvoiceDate: 주문 날짜
  • UnitPrice: 상품 가격
  • CustomerID: 고객 아이디
  • Country: 고객 거주지역(국가)
  • .isnull().sum() : null값이 몇개 있는지 확인
pd.options.display.max_rows = 10

# 각 컬럼당 null이 몇 개 있는지 확인
retail.isnull().sum()

InvoiceNo           0
StockCode           0
Description      1454
Quantity            0
InvoiceDate         0
UnitPrice           0
CustomerID     135080
Country             0
dtype: int64

 

  • null 값, 불필요한 데이터 처리
# 비회원을 제거(null이 없는 행만 저장)
retail = retail[pd.notnull(retail['CustomerID'])]

#'CustomerID'에 null이었던 행 사라짐 확인
len(retail)
// 406829
# 구입 수량이 0이하인 데이터를 확인
retail[retail['Quantity'] <= 0]

# 구입 수량이 1 이상인 데이터만 재저장
retail = retail[retail['Quantity'] >= 1]

# len으로 행 사라진 것 확인
len(retail)
// 397924
# 구입 가격이 0 이하인 데이터를 확인
retail[retail['UnitPrice'] <= 0]

# 구입 가격이 1 이상인 데이터를 저장
retail = retail[retail['UnitPrice'] > 0]

len(retail)
// 397884
  • 다시 데이터 정보 확인
retail.info()

<class 'pandas.core.frame.DataFrame'>
Int64Index: 397884 entries, 0 to 541908
Data columns (total 9 columns):
 #   Column         Non-Null Count   Dtype  
---  ------         --------------   -----  
 0   InvoiceNo      397884 non-null  object 
 1   StockCode      397884 non-null  object 
 2   Description    397884 non-null  object 
 3   Quantity       397884 non-null  int64  
 4   InvoiceDate    397884 non-null  object 
 5   UnitPrice      397884 non-null  float64
 6   CustomerID     397884 non-null  float64
 7   Country        397884 non-null  object 
 8   CheckoutPrice  397884 non-null  float64
dtypes: float64(3), int64(1), object(5)
memory usage: 30.4+ MB
  • 데이터 타입 object => date 타입으로 바꾸기
retail['InvoiceDate'] = pd.to_datetime(retail['InvoiceDate'])

retail.info()

<class 'pandas.core.frame.DataFrame'>
Int64Index: 397884 entries, 0 to 541908
Data columns (total 9 columns):
 #   Column         Non-Null Count   Dtype         
---  ------         --------------   -----         
 0   InvoiceNo      397884 non-null  object        
 1   StockCode      397884 non-null  object        
 2   Description    397884 non-null  object        
 3   Quantity       397884 non-null  int64         
 4   InvoiceDate    397884 non-null  datetime64[ns]   # type변환 성공 확인
 5   UnitPrice      397884 non-null  float64       
 6   CustomerID     397884 non-null  float64       
 7   Country        397884 non-null  object        
 8   CheckoutPrice  397884 non-null  float64       
dtypes: datetime64[ns](1), float64(3), int64(1), object(4)
memory usage: 30.4+ MB
  • 제일 많이 팔리는 판매제품 Top10
top_selling = retail.groupby('StockCode')['Quantity'].sum().sort_values(ascending=False).iloc[:10]
print(top_selling)
StockCode
23843     80995
23166     77916
84077     54415
22197     49183
85099B    46181
85123A    36782
84879     35362
21212     33693
23084     27202
22492     26076
Name: Quantity, dtype: int64
  • checkoutPrice기준 우수고객 Top10
vip = retail.groupby('CustomerID')['CheckoutPrice'].sum().sort_values(ascending=False).head(10)
vip
CustomerID
14646.0    280206.02
18102.0    259657.30
17450.0    194550.79
16446.0    168472.50
14911.0    143825.06
12415.0    124914.53
14156.0    117379.63
17511.0     91062.38
16029.0     81024.84
12346.0     77183.60
Name: CheckoutPrice, dtype: float64
  • 나라별 매출 구하기
# 전체 매출 확인
total_revenue = retail['CheckoutPrice'].sum()
total_revenue
# 각 나라별 구매 횟수
retail['Country'].value_counts()
# 국가별 매출
rev_by_countries = retail.groupby('Country')['CheckoutPrice'].sum().sort_values()

Country
Saudi Arabia          145.920
Bahrain               548.400
Czech Republic        826.740
RSA                  1002.310
Brazil               1143.600
                     ...     
France             209024.050
Germany            228867.140
EIRE               265545.900
Netherlands        285446.340
United Kingdom    7308391.554
Name: CheckoutPrice, Length: 37, dtype: float64
# pandas도 matplotlib 기능이 어느정도 있음
plot = rev_by_countries.plot(kind='bar', figsize=(20, 10))
plot.set_xlabel('Country', fontsize=12)
plot.set_ylabel('Revenue', fontsize=12)
plot.set_title('Revenue By Country', fontsize=15)
plot.set_xticklabels(labels=rev_by_countries.index, rotation=45)

# 나라별 매출/ 총 매출 >> 나라별 매출이 차지하는 비율
rev_by_countries / total_revenue

Country
Saudi Arabia      0.000016
Bahrain           0.000062
Czech Republic    0.000093
RSA               0.000112
Brazil            0.000128
                    ...   
France            0.023456
Germany           0.025682
EIRE              0.029798
Netherlands       0.032032
United Kingdom    0.820116
Name: CheckoutPrice, Length: 37, dtype: float64
  • 월별 매출 구하기
retail['InvoiceDate'].sort_values(ascending=False)

541908   2011-12-09 12:50:00
541901   2011-12-09 12:50:00
541895   2011-12-09 12:50:00
541896   2011-12-09 12:50:00
541897   2011-12-09 12:50:00
                 ...        
3        2010-12-01 08:26:00
1        2010-12-01 08:26:00
5        2010-12-01 08:26:00
6        2010-12-01 08:26:00
0        2010-12-01 08:26:00
Name: InvoiceDate, Length: 397884, dtype: datetime64[ns]
# 년도와 월로 groupby 후 매출의 합 구함
retail.groupby([retail['InvoiceDate'].dt.year,retail['InvoiceDate'].dt.month])['CheckoutPrice'].sum()

InvoiceDate  InvoiceDate
2010         12              572713.890
2011         1               569445.040
             2               447137.350
             3               595500.760
             4               469200.361
                               ...     
             8               645343.900
             9               952838.382
             10             1039318.790
             11             1161817.380
             12              518192.790
Name: CheckoutPrice, Length: 13, dtype: float64
# 년도와 월 이름 변경하는 함수
def extract_month(date): # 2011-12-09 12:50:00
    month = str(date.month) #12
    if date.month < 10:
        month = '0' + month # 01
    return str(date.year) + month #201112

✔ groupby 안에 extrack_month 함수를 넣은 모습입니다. 

rev_by_month = retail.set_index('InvoiceDate').groupby(extract_month)['CheckoutPrice'].sum()

InvoiceDate
201012     572713.890
201101     569445.040
201102     447137.350
201103     595500.760
201104     469200.361
             ...     
201108     645343.900
201109     952838.382
201110    1039318.790
201111    1161817.380
201112     518192.790
Name: CheckoutPrice, Length: 13, dtype: float64

https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.groupby.html#pandas.DataFrame.groupby

 

pandas.DataFrame.groupby — pandas 2.1.4 documentation

Split along rows (0) or columns (1). For Series this parameter is unused and defaults to 0. Deprecated since version 2.1.0: Will be removed and behave like axis=0 in a future version. For axis=1, do frame.T.groupby(...) instead.

pandas.pydata.org

groupby 메서드의 by 매개변수가 함수일 경우 해당 객체의 인덱스의 각 값에 대해 groupby가 호출됩니다.

 

# 요일별 매출 구하기
def extract_dow(date):
    return date.dayofweek
    
rev_by_dow= retail.set_index('InvoiceDate').groupby(lambda date: date.dayofweek)['CheckoutPrice'].sum()
InvoiceDate
0    1367146.411
1    1700634.631
2    1588336.170
3    1976859.070
4    1485917.401
6     792514.221
Name: CheckoutPrice, dtype: float64
import numpy as np
# 요일은 0~6으로 변환되기 때문에 요일 이름으로 변경해주기

DAY_OF_WEEK = np.array(['Mon', 'Tue', 'Web',"Thur", ' Fri', 'Sat', 'Sun'])

# rev_by_dow의 인덱스 = DAY_OF_WEEK[0~6]
rev_by_dow.index = DAY_OF_WEEK[rev_by_dow.index]

rev_by_dow.index // Index(['Mon', 'Tue', 'Web', 'Thur', ' Fri', 'Sun'], dtype='object')

rev_by_dow
Mon     1367146.411
Tue     1700634.631
Web     1588336.170
Thur    1976859.070
 Fri    1485917.401
Sun      792514.221
Name: CheckoutPrice, dtype: float64
plot_bar(rev_by_dow, 'DOW', 'Revenue', 'Revenue By DOW')

# 시간대별 매출 구하기
rev_by_hour= retail.set_index('InvoiceDate').groupby(lambda date: date.hour)['CheckoutPrice'].sum()

print(rev_by_hour)
InvoiceDate
6           4.250
7       31059.210
8      282115.630
9      842605.171
10    1261192.571
         ...     
16     468885.800
17     234413.521
18     104954.430
19      49028.460
20      18932.760
Name: CheckoutPrice, Length: 15, dtype: float64
plot_bar(rev_by_hour, 'Hour', 'Revenue', 'Revenue By Hour')

데이터로부터 통찰한 결과

* 전체 매출의 약 82%가 UK에서 발생
* 매출은 꾸준히 성장하는 것으로 예상
(11년 12월 데이터는 9일까지만 포함)
* 토요일은 영업을 하지 않음
* 새벽 6시에 오픈, 오후 9시에 마감이 예상
* 일주일 중 목요일까지는 성장세를 보이고 이후 하락
* 점심시간대 매출이 높음

 

'데이터 분석' 카테고리의 다른 글

boxplot / 따릉이 실시간 데이터 예제  (0) 2023.12.24
상권별 업종 밀집 통계 예제  (0) 2023.12.23
Matplotlib  (0) 2023.12.10
판다스3  (0) 2023.12.08
판다스2  (0) 2023.12.08