主頁 > 後端開發 > python連接Mysql共享汽車行業案例分析

python連接Mysql共享汽車行業案例分析

2021-03-06 10:40:00 後端開發

學習記錄——共享汽車分析

前言

  1. 本文僅記錄個人學習程序寫的代碼供自己復盤使用,如果對你有幫助和啟發那就更好了,
  2. 新人作品,歡迎討論和斧正,大神輕噴,
  3. 純代碼實作,無結論,
  4. 一些相似的維度舉一反三就行,
  5. 需要資料集練習的可以留言

目標

  1. python, mysql, matplotlib 代碼練習
  2. 常用資料指標的實作

資料匯入

python 連接資料庫 Mysql

#獲取資料方法
import pymysql 
import pandas as pd 
from matplotlib import pyplot as plt
from matplotlib import font_manager

def get_mysql_data(DB, sql):
    conn = pymysql.connect(host=DB['host'], port=DB['port'], user=DB['user'], password=DB['password'], database=DB['dbname'])
 
    # 創建游標
    cursor = conn.cursor()
    # 執行sql陳述句
    cursor.execute(sql)
    # 調出資料
    data = cursor.fetchall()
    # cols為欄位資訊 
    cols = cursor.description
    # 將資料轉換為DataFrame
    col = []
    for i in cols:
        col.append(i[0])
    # data轉成list形式 
    data = list(map(list, data))
    data = pd.DataFrame(data,columns=col)
    # 關閉游標以及連接
    cursor.close()
    conn.close()
    return data

日期時間處理——獲取年月日時維度

def time_data(data):
        
    data['下單年'] = data["下單時間"].astype("str").apply(lambda x: x.split('-')[0]) 
    data['下單年月'] = data["下單時間"].astype("str").apply(lambda x: x.split('-')[0]+"/"+x.split('-')[1])
    data['下單月'] = data["下單時間"].astype("str").apply(lambda x: x.split('-')[1])
    data['下單日'] = data["下單時間"].astype("str").apply(lambda x: x.split('-')[2]) 
    data['下單時'] = data["下單時間"].astype("str").apply(lambda x: x.split('-')[0]) 
    data['付款年'] = data["付款日期"].astype("str").apply(lambda x: x.split('-')[0]) 
    data['付款年月'] = data["付款日期"].astype("str").apply(lambda x: x.split('-')[0]+"/"+x.split('-')[1])
    data['付款月'] =data["付款日期"].astype("str").apply(lambda x: x.split('-')[1])
    data['付款日'] = data["付款日期"].astype("str").apply(lambda x: x.split('-')[2]) 
    data['付款時'] = data["付款日期"].astype("str").apply(lambda x: x.split('-')[0]) 
    return data



DB = { 'host':"127.0.0.1",'port':3306, 'user':'root','password':'password','dbname':'datebase'}

留存分析

# 留存分析
SQL='''select *,
concat(ROUND(100*次日留存用戶數/榷訓躍用戶數),"%") 次日留存率,
concat(ROUND(100*三日留存用戶數/榷訓躍用戶數),"%") 三日留存率,
concat(ROUND(100*七日留存用戶數/榷訓躍用戶數),"%") 七日留存率
from(
select date(a.`付款時間`) 日期 ,DATE_FORMAT(a.`付款時間`,"%H") 時間,
COUNT(DISTINCT a.`用戶ID`) 榷訓躍用戶數,
COUNT(DISTINCT b.`用戶ID`) 次日留存用戶數,
COUNT(DISTINCT c.`用戶ID`) 三日留存用戶數,
COUNT(DISTINCT d.`用戶ID`) 七日留存用戶數
from paper_data a 
left join paper_data b 
on  a.`用戶ID`=b.`用戶ID`
and date(b.`付款時間`)=date(a.`付款時間`)+1
left join paper_data c
on  a.`用戶ID`=c.`用戶ID`
and date(c.`付款時間`)=date(a.`付款時間`)+3
left join paper_data d
on  a.`用戶ID`=d.`用戶ID`
and date(d.`付款時間`)=date(a.`付款時間`)+7
where a.`付款時間` between "2020-01-01" and "2020-01-31"
GROUP BY date(a.`付款時間`)
)f;'''
liuchun = get_mysql_data(DB, SQL)
liuchun
x=liuchun['日期']
y1=liuchun['次日留存率']
y2=liuchun['三日留存率']
y3=liuchun['七日留存率']
plt.figure(figsize=(25,10),dpi=80)
my_font = font_manager.FontProperties(fname="C:/Users/wty_pc/Anaconda3/Lib/site-packages/matplotlib/mpl-data/fonts/ttf/STSONG.TTF",size = 18)
rects1=plt.plot(x,y1,color="red",alpha=0.5,linestyle="-",linewidth=3,label="次日留存率")
rects2=plt.plot(x,y2,color="g",alpha=0.5,linestyle="-",linewidth=3,label="三日留存率")
rects3=plt.plot(x,y3,color="b",alpha=0.5,linestyle="-",linewidth=3,label="七日留存率")
rects4=plt.legend(prop=my_font,loc="best")
for i in range(len(x)):
        plt.text(x[i],y1[i],y1[i],fontsize=15,ha="center")

for i in range(len(x)):
        plt.text(x[i],y2[i],y2[i],fontsize=15,ha="center")
for i in range(len(x)):
        plt.text(x[i],y3[i],y3[i],fontsize=15,ha="center")
        
plt.show()


留存分析

訂單分析

訂單分析(可以把訂單換成其他的,比如用戶數,銷售量等資料)

# 1.根據下單的時間來統計訂單量
# (1)年維度
SQL='''select date_format(付款時間,"%Y")下單年 ,count(訂單ID) as 訂單量 from paper_data group by date_format(付款時間,"%Y")'''
order_num_year=get_mysql_data(DB, SQL)

my_font = font_manager.FontProperties(fname="C:/Users/wty_pc/Anaconda3/Lib/site-packages/matplotlib/mpl-data/fonts/ttf/STSONG.TTF",size = 18)
x=order_num_year["下單年"]
y=order_num_year["訂單量"]
plt.figure(figsize=(20,8),dpi=80)
rects = plt.bar(x,y,width=0.3,color="b",label="2019")
# 標注
for rect in rects:
    height=rect.get_height()
    plt.text(rect.get_x()+rect.get_width()/2,height+0.3,str(height),ha="center")
plt.title("年度訂單量",FontProperties=my_font)
plt.xlabel("年份",FontProperties=my_font)
plt.ylabel("訂單量",FontProperties=my_font)
plt.legend(prop=my_font,loc="best")
plt.show()

在這里插入圖片描述

# 訂單分析
# 1.根據下單的時間來統計訂單量
# (2)年月維度
SQL='''select date_format(付款時間,"%Y/%m")下單年月 ,count(訂單ID) as 訂單量 from paper_data group by date_format(付款時間,"%Y/%m")'''
order_num_month=get_mysql_data(DB, SQL)

my_font = font_manager.FontProperties(fname="C:/Users/wty_pc/Anaconda3/Lib/site-packages/matplotlib/mpl-data/fonts/ttf/STSONG.TTF",size = 18)
x=order_num_month["下單年月"]
y=order_num_month["訂單量"]
plt.figure(figsize=(20,8),dpi=80)
rects = plt.bar(x,y,width=0.3,color=["r","g","b"])
# 標注
for rect in rects:
    height=rect.get_height()
    plt.text(rect.get_x()+rect.get_width()/2,height+0.3,str(height),ha="center")
plt.show()

在這里插入圖片描述

# (3)年月、城市維度(折線圖)
SQL='''select date_format(下單時間,"%Y/%m")下單年月 ,城市,count(訂單ID) as 訂單量 
from paper_data
group by date_format(下單時間,"%Y/%m"),城市
order by date_format(下單時間,"%Y/%m");
'''
order_num_month1=get_mysql_data(DB, SQL)



#把每個城市的資料取出來
order_month_city=order_num_month1.groupby(["城市"])
order_shanghai=order_month_city.get_group("上海").reset_index(drop="true")
order_beijing=order_month_city.get_group("北京").reset_index(drop="true")
order_hangzhou=order_month_city.get_group("杭州").reset_index(drop="true")
order_xian=order_month_city.get_group("西安").reset_index(drop="true")


# matplotlib畫圖部分
my_font = font_manager.FontProperties(fname="C:/Users/wty_pc/Anaconda3/Lib/site-packages/matplotlib/mpl-data/fonts/ttf/STSONG.TTF",size = 18)
plt.figure(figsize=(25,10),dpi=80)

plt.plot(order_shanghai["下單年月"],order_shanghai["訂單量"],marker='o',color="r",label="上海訂單量")
plt.plot(order_beijing["下單年月"],order_beijing["訂單量"],marker='v',color="g",label="北京訂單量")
plt.plot(order_hangzhou["下單年月"],order_hangzhou["訂單量"],marker='^',color="b",label="杭州訂單量")
plt.plot(order_xian["下單年月"],order_xian["訂單量"],marker='.',color="y",label="西安訂單量")
plt.xlabel("時間",FontProperties=my_font)
plt.ylabel("訂單量",FontProperties=my_font)
plt.title("各城市每月訂單量",FontProperties=my_font)
plt.legend(prop=my_font,loc="best")



#  df.idxmax()默認值是0,求列最大值的行索引,1就是反過來
def city_max(df):
    return df.idxmax()



# 最大值標記
plt.text(order_shanghai["下單年月"].iloc[city_max(order_shanghai["訂單量"])],order_shanghai.max()["訂單量"]+5,"上海最大訂單:{}".format(order_shanghai.max()["訂單量"]),fontsize=12,ha="center",color="r",FontProperties=my_font)
plt.text(order_beijing["下單年月"].iloc[city_max(order_beijing["訂單量"])],order_beijing.max()["訂單量"]+5,"北京最大訂單:{}".format(order_beijing.max()["訂單量"]),fontsize=12,ha="center",color="g",FontProperties=my_font)
plt.text(order_hangzhou["下單年月"].iloc[city_max(order_hangzhou["訂單量"])],order_hangzhou.max()["訂單量"]+5,"杭州最大訂單:{}".format(order_hangzhou.max()["訂單量"]),fontsize=12,ha="center",color="b",FontProperties=my_font)
plt.text(order_xian["下單年月"].iloc[city_max(order_xian["訂單量"])],order_xian.max()["訂單量"]+5,"西安最大訂單:{}".format(order_xian.max()["訂單量"]),fontsize=12,ha="center",color="y",FontProperties=my_font)
plt.show()


# -----------------------------

# 每年、每月的一樣的做法,改下日期欄位就好


在這里插入圖片描述

# (3)年城市維度(柱狀圖)
SQL='''select date_format(付款時間,"%Y")下單年,城市,count(訂單ID) as 訂單量 
from paper_data
group by date_format(付款時間,"%Y"),城市
order by date_format(付款時間,"%Y");
'''
order_num_year=get_mysql_data(DB, SQL)
# order_num_month.describe()

# 按城市拆分資料
order_year_city=order_num_year.groupby(["城市"])
order_shanghai=order_year_city.get_group("上海").reset_index(drop="true")
order_beijing=order_year_city.get_group("北京").reset_index(drop="true")
order_hangzhou=order_year_city.get_group("杭州").reset_index(drop="true")
order_xian=order_year_city.get_group("西安").reset_index(drop="true")

# -----matplotlib畫圖部分------
my_font = font_manager.FontProperties(fname="C:/Users/wty_pc/Anaconda3/Lib/site-packages/matplotlib/mpl-data/fonts/ttf/STSONG.TTF",size = 18)
plt.figure(figsize=(25,10),dpi=80)
# 設定柱子位置,通過偏移量a來實作,
# 由于時間是datetime型別或者object(str)型別的不能直接加偏移量所以這里用長度長度實作柱子的位置,然后把刻度值重新設定 
a=0.2 
x_01=list(range(len(order_shanghai["下單年"])))
x_02=[i+a for i in x_01]
x_03=[i-2*a for i in x_01]
x_04=[i-a for i in x_01]


# 畫圖
rects1=plt.bar(x_01,order_shanghai["訂單量"],a,color="r",align='edge',label="上海訂單量")
rects2=plt.bar(x_02,order_beijing["訂單量"],a,color="g",align='edge',label="北京訂單量")
rects3=plt.bar(x_03,order_hangzhou["訂單量"],a,color="b",align='edge',label="杭州訂單量")
rects4=plt.bar(x_04,order_xian["訂單量"],a,color="y",align='edge',label="西安訂單量")

# x軸刻度
plt.xticks(x_01,labels=order_shanghai["下單年"])

# 軸名稱
plt.xlabel("年份",FontProperties=my_font)
plt.ylabel("訂單量",FontProperties=my_font)
# 標題
plt.title("各城市每月訂單量",FontProperties=my_font)
# 圖例
plt.legend(prop=my_font,loc="best")
# 標記
def mark_bar(rects):
    for rect in rects:
        height=rect.get_height()
        plt.text(rect.get_x()+rect.get_width()/2,height+0.3,str(height),fontsize=15,ha="center")
mark_bar(rects1)
mark_bar(rects2)
mark_bar(rects3)
mark_bar(rects4)
plt.show()

在這里插入圖片描述

# 3、小時訂單量分布情況
SQL= '''SELECT date_format(下單時間,"%H")  下單時, count(`訂單ID`) 訂單量
from paper_data
where  date_format(下單時間,"%Y-%m")="2020-01"
GROUP BY date_format(下單時間,"%H") 
ORDER BY date_format(下單時間,"%H") 
;'''

h_dingdan=get_mysql_data(DB, SQL)


my_font = font_manager.FontProperties(fname="C:/Users/wty_pc/Anaconda3/Lib/site-packages/matplotlib/mpl-data/fonts/ttf/STSONG.TTF",size = 18)
plt.figure(figsize=(25,10),dpi=80)
x=h_dingdan["下單時"]
y=h_dingdan["訂單量"]
plt.plot(x,y,color="r",label="每小時訂單量")
# 設定標記
for a,b  in zip(x,y):
    #a x坐標, b坐標, (a,b) 一個點 
    # ha 水平方向  va 垂直方向  fontsize 大小 
    plt.text(a,b,b ,ha='center',va='bottom', fontsize=12)
#設定刻度
xtick_labels = ['{}:00'.format(i) for i in x]
plt.xticks(x,xtick_labels)
#設定坐標名稱
plt.xlabel("時間",FontProperties=my_font)
plt.ylabel("訂單量",FontProperties=my_font)
#設定表名
plt.title("1月每小時訂單量",FontProperties=my_font)
#設定圖例
plt.legend(prop=my_font,loc="best")
plt.show()

RFM模型

#RMF分層
SQL='''SELECT 用戶ID,COUNT(訂單ID) AS F,round(sum(實收金額),2) AS M,date_format(max(付款時間),"%Y/%m/%d") as R 
            FROM paper_data GROUP BY 用戶ID ORDER BY 用戶ID
            ;'''
User_layer=get_mysql_data(DB, SQL)
# RMF評分公式

# User_layer["R1"]=((pd.to_datetime("2020/03-01")-pd.to_datetime(User_layer["R"])) 后面的處理方式是為了把timedelta型別轉換成Int型別
User_layer["R1"]=((pd.to_datetime("2020/03-01")-pd.to_datetime(User_layer["R"]))/pd.Timedelta(1,"D")).fillna(0).astype(int)
User_layer["RR"]=(pd.to_datetime(User_layer["R"])-pd.to_datetime(min(User_layer["R"])))/((pd.to_datetime(max(User_layer["R"]))-pd.to_datetime(min(User_layer["R"]))))
User_layer["FF"]=(User_layer["F"]-min(User_layer["F"]))/(max(User_layer["F"])-min(User_layer["F"]))
User_layer["MM"]=(User_layer["M"]-min(User_layer["M"]))/(max(User_layer["M"])-min(User_layer["M"]))
User_layer["SCORE"]=100*(0.25*User_layer["FF"]+0.6*User_layer["MM"]+0.15*User_layer["RR"])
User_layer
用戶IDFMRR1RRFFMMSCORE
01323517.02021/01/25-3300.9805190.6739130.66395371.392801
110292600.02021/01/23-3280.9779220.6086960.49034559.306896
2100313906.02021/01/11-3160.9623380.6521740.73759974.995376
31000242255.02021/01/07-3120.9571430.5000000.42502852.358847
410009171.02019/04/093270.1272730.0000000.0115492.602010
..............................
59249977119.02020/10/27-2400.8636360.0000000.00170413.056779
5925998343634.02021/02/06-3420.9961040.7173910.68610474.042566
5926999333356.02021/01/27-3320.9831170.6956520.63347270.146388
592799931125.02020/11/04-2480.8740260.0000000.02177214.416713
592899941135.02020/08/22-1740.7779220.0000000.02366513.088748

5929 rows × 9 columns

# 根據權重SCORE四分位分組的依據
User_describe=User_layer.describe()
User_describe
FMR1RRFFMMSCORE
count5929.0000005929.0000005929.0000005929.0000005929.0000005929.0000005929.000000
mean10.9790861148.957160-117.5140830.7045640.2169370.21563028.929667
std13.6568801440.872815228.5950260.2968770.2968890.27278926.743116
min1.00000010.000000-345.0000000.0000000.0000000.0000000.185039
25%1.000000112.000000-318.0000000.4896100.0000000.0193118.927758
50%2.000000198.000000-208.0000000.8220780.0217390.03559314.496745
75%26.0000002679.00000048.0000000.9649350.5434780.50530158.371452
max47.0000005292.000000425.0000001.0000001.0000001.00000097.960474
# df遍歷后的結果最好用list/dict存放起來,df本身一個一個添加資料遍歷效率不高,而且難取數,最好用List/dict整體取賦值
list_level=[]
for index ,rows in User_layer.iterrows():
#     print("索引是:",index,"資料是:",rows)
    if  rows["SCORE"]<=User_describe.loc["25%"]["SCORE"]:
        rows["level"]="四等"
        
    elif  rows["SCORE"]<=User_describe.loc["50%"]["SCORE"]:
        rows["level"]="三等"
        
    elif  rows["SCORE"]<=User_describe.loc["75%"]["SCORE"]:
        rows["level"]="二等"
        
    else:
        rows["level"]="一等"  
    list_level.append(rows["level"])
    
User_layer['level']=list_level
User_layer



用戶IDFMRR1RRFFMMSCORElevel
01323517.02021/01/25-3300.9805190.6739130.66395371.392801一等
110292600.02021/01/23-3280.9779220.6086960.49034559.306896一等
2100313906.02021/01/11-3160.9623380.6521740.73759974.995376一等
31000242255.02021/01/07-3120.9571430.5000000.42502852.358847二等
410009171.02019/04/093270.1272730.0000000.0115492.602010四等
.................................
59249977119.02020/10/27-2400.8636360.0000000.00170413.056779三等
5925998343634.02021/02/06-3420.9961040.7173910.68610474.042566一等
5926999333356.02021/01/27-3320.9831170.6956520.63347270.146388一等
592799931125.02020/11/04-2480.8740260.0000000.02177214.416713三等
592899941135.02020/08/22-1740.7779220.0000000.02366513.088748三等

5929 rows × 10 columns

用戶標簽


# 用戶打標簽
SQL='''select 用戶ID,count(*) as order_num,count(date_format(付款時間,"%M")) 月數,
                  sum(case when 取車型別='自取' then 1 else 0 end) as 自取次數,
                  sum(case when 優惠金額>1 then 1 else 0 end) as 優惠券使用次數,
                  sum(case when 非網點還車費>0 then 1 else 0 end) as  還車次數
                  from paper_data 
                  group by 用戶ID
                  ;
'''

bq=get_mysql_data(DB, SQL)

data_total=pd.merge(User_layer,bq,on="用戶ID")

data_total
# print(data_total["FF"].dtypes,data_total["自取次數"].dtypes)
for index,row in data_total.iterrows():
# 取車
    if row["FF"]==0:
        row["FF"]= row["FF"]+0.0001
# Int/浮點數會報錯,注意轉換型別
        if float(row["自取次數"])/row["FF"]>0.5:
            data_total["取車偏好"]="時租居多"
        else:
            data_total["取車偏好"]="日租居多"
    #       網點還車  
        if float(row["還車次數"])/row["FF"]>0.5:
            data_total["還車偏好"]="非網點還車"
        else:
            data_total["還車偏好"]="網點還車"
    #     月均訂單
        if row["FF"]/row["月數"]>6:
            data_total["月均單量"]="月均單量大于6"
        else:
            data_total["月均單量"]="月均單量小于6"

data_total

   

用戶IDFMRR1RRFFMMSCORElevelorder_num月數自取次數優惠券使用次數還車次數取車偏好還車偏好月均單量
01323517.02021/01/25-3300.9805190.6739130.66395371.392801一等3232112313時租居多網點還車月均單量小于6
110292600.02021/01/23-3280.9779220.6086960.49034559.306896一等2929162412時租居多網點還車月均單量小于6
2100313906.02021/01/11-3160.9623380.6521740.73759974.995376一等313112217時租居多網點還車月均單量小于6
31000242255.02021/01/07-3120.9571430.5000000.42502852.358847二等2424131511時租居多網點還車月均單量小于6
410009171.02019/04/093270.1272730.0000000.0115492.602010四等11101時租居多網點還車月均單量小于6
.........................................................
59249977119.02020/10/27-2400.8636360.0000000.00170413.056779三等11010時租居多網點還車月均單量小于6
5925998343634.02021/02/06-3420.9961040.7173910.68610474.042566一等3434182413時租居多網點還車月均單量小于6
5926999333356.02021/01/27-3320.9831170.6956520.63347270.146388一等3333121910時租居多網點還車月均單量小于6
592799931125.02020/11/04-2480.8740260.0000000.02177214.416713三等11011時租居多網點還車月均單量小于6
592899941135.02020/08/22-1740.7779220.0000000.02366513.088748三等11100時租居多網點還車月均單量小于6

5929 rows × 18 columns

用戶生命周期

def user_life(data,a,b,c):
    list_1=[]
    for index,row in data.iterrows():
#         print(row[a])
#         print(index)
        if row[a]==1:
            row[c]="引入期"
        elif row[a]>1 and row[a]<3 and row[b]<=200:
            row[c]="成長期"
        elif row[a]>=3 and row[b]<=300:
            row[c]="休眠期"
        elif row[b]>300:
            row[c]="流失期"
        else:
            row[c]="其他"
#         print(row[c])
        list_1.append(row)
    data_1=pd.DataFrame(list_1)
#     print(data_1)
    return data_1


Userlife=pd.DataFrame()
Userlife=user_life(data_total,"F","R1","生命周期")
Userlife.head(10)


用戶IDFMRR1RRFFMMSCORElevelorder_num月數自取次數優惠券使用次數還車次數取車偏好還車偏好月均單量生命周期
01323517.02021/01/25-3300.9805190.6739130.66395371.392801一等3232112313時租居多網點還車月均單量小于6休眠期
110292600.02021/01/23-3280.9779220.6086960.49034559.306896一等2929162412時租居多網點還車月均單量小于6休眠期
2100313906.02021/01/11-3160.9623380.6521740.73759974.995376一等313112217時租居多網點還車月均單量小于6休眠期
31000242255.02021/01/07-3120.9571430.5000000.42502852.358847二等2424131511時租居多網點還車月均單量小于6休眠期
410009171.02019/04/093270.1272730.0000000.0115492.602010四等11101時租居多網點還車月均單量小于6引入期
51001283074.02021/01/24-3290.9792210.5869570.58008364.167223一等2828121812時租居多網點還車月均單量小于6休眠期
610014149.02020/08/25-1770.7818180.0000000.00738412.170287三等11110時租居多網點還車月均單量小于6引入期
710016167.02020/07/19-1400.7337660.0000000.01079111.653976三等11010時租居多網點還車月均單量小于6引入期
81002293316.02021/01/03-3080.9519480.6086960.62589967.050569一等2929121915時租居多網點還車月均單量小于6休眠期
910023181.02020/09/09-1920.8012990.0000000.01344212.825993三等11110時租居多網點還車月均單量小于6引入期
"休眠期" in Userlife["生命周期"].values
True
zq=Userlife.groupby("生命周期")
yr=zq.get_group("引入期")["生命周期"].count()
cz=zq.get_group("成長期")["生命周期"].count()
xm=zq.get_group("休眠期")["生命周期"].count()
ls=zq.get_group("流失期")["生命周期"].count()

x=["引入期","成長期","休眠期","流失期"]
y=[yr,cz,xm,ls]
for i in range(len(x)):
    print(x[i],y[i])

my_font = font_manager.FontProperties(fname="C:/Users/wty_pc/Anaconda3/Lib/site-packages/matplotlib/mpl-data/fonts/ttf/STSONG.TTF",size = 18)
plt.figure(figsize=(25,10),dpi=80)
plt.rcParams['font.sans-serif']=['STSONG'] #中文標簽設定
# plt.rcParams['axes.unicode_minus']=False  #用來正常顯示坐標負號
rects=plt.bar(x,y,0.3,color=["r","g","b","y"])
plt.xticks(x,x,fontproperties=my_font)

for rect in rects:
    height=rect.get_height()
    plt.text(rect.get_x()+rect.get_width()/2,height+1,str(height),fontsize=18,ha="center")


plt.show()
引入期 2528
成長期 895
休眠期 2414
流失期 32

在這里插入圖片描述

用戶評分統計

# 評分 
#0分代表未參與評分,可以統計用戶的參與度

SQL='''select date_format(付款時間,"%Y/%m") 付款年月,評分,count(distinct 用戶ID) as user_num,count(*) as order_num 
                   from paper_data group by date_format(付款時間,"%Y/%m"),評分;'''


pinfen_num=get_mysql_data(DB,SQL)
pinfen_num["評分"]=pinfen_num["評分"].astype(int)
pinfen_num["參與度"]=pinfen_num["user_num"]/pinfen_num["order_num"]
pinfen_num.dtypes

付款年月          object
評分             int32
user_num       int64
order_num      int64
參與度          float64
dtype: object
# 用戶評分參與度=有評分的用戶/下單用戶量
import numpy as np
# 按評分分組
pf_group=pinfen_num.groupby(["評分"])

# id_name
# 取出分組的值
# 方法一
list_pf=[]
for key,value in pf_group:
    list_pf.append(value.reset_index(drop="true"))
# 方法二格式化成串列或者字典,詳見后面一個代碼塊

x=list_pf[0]["付款年月"]
y=[]
for i in range(len(list_pf)):
    y.append(list_pf[i]["參與度"])
# print("x:",x.values)
# print("y:",y[1])


my_font = font_manager.FontProperties(fname="C:/Users/wty_pc/Anaconda3/Lib/site-packages/matplotlib/mpl-data/fonts/ttf/STSONG.TTF",size = 15)
fig=plt.figure(figsize=(20,40),dpi=80)

colors=["r","g","b"]
for i in range(1,12):
    ax=fig.add_subplot(11,1,i)
    ax.plot(x,y[i-1],color=colors[np.random.randint(3)],label="{}分".format(i-1))
    x_label="評分為{}的趨勢".format(i-1)
    ax.set_xlabel(x_label,fontproperties=my_font)
    ax.set_ylabel("參與度",fontproperties=my_font)
    ax.legend()
 #調整子圖間距    
plt.tight_layout()
plt.show()

在這里插入圖片描述

groupby取數的技巧

# groupby 格式化成串列 為轉換成字典做鋪墊

a=list(pinfen_num.groupby(["評分"]))
# 串列的每個元素是個元組,每個元組的值為分組鍵和值(datafarme)
a[0][1].reset_index(drop = True)
# print(type(a[1]))
付款年月評分user_numorder_num參與度
02019/0102302410.954357
12019/0202062130.967136
22019/0302392580.926357
32019/0402092160.967593
42019/0502132230.955157
52019/0602172300.943478
62019/0702292390.958159
72019/0802162220.972973
82019/0902142290.934498
92019/1002322440.950820
102019/1102252350.957447
112019/1202392470.967611
122020/0102712870.944251
132020/0201872000.935000
142020/0302212300.960870
152020/0402162300.939130
162020/0502192270.964758
172020/0602072180.949541
182020/0702242320.965517
192020/0802392500.956000
202020/0902242330.961373
212020/1002402500.960000
222020/1102202270.969163
232020/1202182300.947826
242021/0102382510.948207
252021/02056570.982456
# groupby 格式化成字典
a=dict(list(pinfen_num.groupby(["評分"])))
# type(a[0])
a[0].reset_index(drop=True)
付款年月評分user_numorder_num參與度
02019/0102302410.954357
12019/0202062130.967136
22019/0302392580.926357
32019/0402092160.967593
42019/0502132230.955157
52019/0602172300.943478
62019/0702292390.958159
72019/0802162220.972973
82019/0902142290.934498
92019/1002322440.950820
102019/1102252350.957447
112019/1202392470.967611
122020/0102712870.944251
132020/0201872000.935000
142020/0302212300.960870
152020/0402162300.939130
162020/0502192270.964758
172020/0602072180.949541
182020/0702242320.965517
192020/0802392500.956000
202020/0902242330.961373
212020/1002402500.960000
222020/1102202270.969163
232020/1202182300.947826
242021/0102382510.948207
252021/02056570.982456
pinfen_num.groupby(["評分"]).size()
評分
0     26
1     26
2     26
3     26
4     26
5     26
6     26
7     26
8     26
9     26
10    26
dtype: int64
pinfen_num.groupby(["評分"]).count()
付款年月user_numorder_num參與度
評分
026262626
126262626
226262626
326262626
426262626
526262626
626262626
726262626
826262626
926262626
1026262626
# 每個評分最小參與度

pinfen_num["參與度"].groupby(pinfen_num["評分"]).min()
pinfen_num.groupby(pinfen_num["評分"]).min()["參與度"]
pinfen_num.groupby(pinfen_num["評分"])["參與度"].min()
評分
0     0.926357
1     0.923695
2     0.917749
3     0.925620
4     0.912000
5     0.934694
6     0.916318
7     0.929961
8     0.929577
9     0.940092
10    0.928571
Name: 參與度, dtype: float64
# 按評分選取多列
# pinfen_num.groupby(pinfen_num["評分"])[["參與度","order_num"]].min()
pinfen_num[["參與度","order_num"]].groupby(pinfen_num["評分"]).min()
參與度order_num
評分
00.92635757
10.92369547
20.91774967
30.92562061
40.91200062
50.93469468
60.91631852
70.92996162
80.92957765
90.94009248
100.92857166
# 多維分組用unstack可以解成二維表(不堆疊)
a=pinfen_num["參與度"].groupby([pinfen_num["付款年月"],pinfen_num["評分"]]).min().unstack()
a
# a.shape
評分012345678910
付款年月
2019/010.9543570.9500000.9710740.9668050.9678710.9763780.9375000.9615380.9357430.9506170.957806
2019/020.9671360.9389670.9724770.9520000.9463410.9439250.9313730.9444440.9345790.9545450.944954
2019/030.9263570.9451480.9280000.9587160.9397590.9409280.9668050.9306120.9563490.9653680.937799
2019/040.9675930.9668250.9704430.9469030.9255810.9786320.9907410.9495800.9776790.9699570.944700
2019/050.9551570.9539750.9469030.9471540.9745760.9521740.9576270.9491530.9626170.9442060.970588
2019/060.9434780.9236950.9485980.9369370.9488190.9581590.9570310.9652170.9533900.9513270.945378
2019/070.9581590.9504130.9688890.9422220.9500000.9541670.9578060.9358490.9483390.9579830.977876
2019/080.9729730.9375000.9451480.9568970.9736840.9680370.9215690.9707110.9617020.9489360.958506
2019/090.9344980.9778760.9488370.9592760.9728510.9739130.9707320.9508930.9547510.9465650.970588
2019/100.9508200.9699570.9824560.9519650.9274190.9448820.9541280.9605260.9464290.9502070.967611
2019/110.9574470.9495800.9827590.9608700.9423080.9655170.9655170.9601590.9346940.9644670.965217
2019/120.9676110.9406390.9489360.9372380.9670780.9405940.9586780.9299610.9466670.9617020.930736
2020/010.9442510.9456070.9618640.9778760.9434780.9769590.9419090.9655170.9510200.9482070.928571
2020/020.9350000.9678900.9631340.9631150.9733330.9444440.9729730.9347830.9694320.9484980.967136
2020/030.9608700.9859150.9414230.9434780.9414410.9775780.9739130.9636360.9468600.9648440.955157
2020/040.9391300.9272030.9382240.9314520.9521740.9459460.9617020.9591840.9455250.9400920.942387
2020/050.9647580.9354840.9177490.9446640.9780700.9592760.9333330.9638550.9547170.9635630.974684
2020/060.9495410.9590910.9527900.9256200.9515420.9638550.9530520.9641260.9581590.9626170.941909
2020/070.9655170.9662450.9492190.9517540.9120000.9457010.9245280.9556450.9674420.9427480.942652
2020/080.9560000.9397590.9260870.9906100.9310340.9442060.9163180.9547330.9763780.9613730.966038
2020/090.9613730.9600000.9589040.9563320.9449150.9809520.9353450.9372380.9600000.9553570.945607
2020/100.9600000.9353450.9432310.9523810.9267400.9417040.9649120.9360000.9314520.9547510.956140
2020/110.9691630.9688720.9523810.9466670.9189190.9601590.9422220.9647580.9295770.9551570.947581
2020/120.9478260.9515420.9579830.9466670.9675930.9517540.9481130.9581750.9517540.9487180.959016
2021/010.9482070.9363640.9612070.9317270.9501920.9346940.9670780.9566930.9610890.9574470.944444
2021/020.9824560.9787230.9701490.9836071.0000000.9705881.0000001.0000000.9692311.0000000.984848
#多維分組堆疊成多索引 
b=pinfen_num["參與度"].groupby([pinfen_num["付款年月"],pinfen_num["評分"]]).min()
b
# b.shape
付款年月     評分
2019/01  0     0.954357
         1     0.950000
         2     0.971074
         3     0.966805
         4     0.967871
                 ...   
2021/02  6     1.000000
         7     1.000000
         8     0.969231
         9     1.000000
         10    0.984848
Name: 參與度, Length: 286, dtype: float64
pinfen_num["參與度"].groupby(pinfen_num["評分"]).describe().unstack()
       評分
count  0     26.000000
       1     26.000000
       2     26.000000
       3     26.000000
       4     26.000000
               ...    
max    6      1.000000
       7      1.000000
       8      0.977679
       9      1.000000
       10     0.984848
Length: 88, dtype: float64
pinfen_num["參與度"].groupby(pinfen_num["評分"]).describe()
countmeanstdmin25%50%75%max
評分
026.00.9553720.0131880.9263570.9479210.9567230.9653270.982456
126.00.9524080.0166140.9236950.9391650.9502070.9666800.985915
226.00.9541870.0164780.9177490.9455860.9525850.9674500.982759
326.00.9524200.0155170.9256200.9437750.9518600.9591360.990610
426.00.9510660.0211230.9120000.9401800.9494090.9678021.000000
526.00.9575050.0143770.9346940.9445540.9561630.9699500.980952
626.00.9540350.0204230.9163180.9386020.9573290.9664831.000000
726.00.9547300.0152480.9299610.9456210.9574340.9638011.000000
826.00.9532910.0132830.9295770.9464880.9540530.9615490.977679
926.00.9565100.0118250.9400920.9487730.9549540.9623881.000000
1026.00.9549200.0148030.9285710.9445080.9556490.9668620.984848

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/266679.html

標籤:python

上一篇:<Notes>Python_Multithreading

下一篇:leetcode541. 反轉字串 II(字串一律用py秒殺)

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Rust中的智能指標:Box<T> Rc<T> Arc<T> Cell<T> RefCell<T> Weak

    Rust中的智能指標是什么 智能指標(smart pointers)是一類資料結構,是擁有資料所有權和額外功能的指標。是指標的進一步發展 指標(pointer)是一個包含記憶體地址的變數的通用概念。這個地址參考,或 ” 指向”(points at)一些其 他資料 。參考以 & 符號為標志并借用了他們所 ......

    uj5u.com 2023-04-20 07:24:10 more
  • Java的值傳遞和參考傳遞

    值傳遞不會改變本身,參考傳遞(如果傳遞的值需要實體化到堆里)如果發生修改了會改變本身。 1.基本資料型別都是值傳遞 package com.example.basic; public class Test { public static void main(String[] args) { int ......

    uj5u.com 2023-04-20 07:24:04 more
  • [2]SpinalHDL教程——Scala簡單入門

    第一個 Scala 程式 shell里面輸入 $ scala scala> 1 + 1 res0: Int = 2 scala> println("Hello World!") Hello World! 檔案形式 object HelloWorld { /* 這是我的第一個 Scala 程式 * 以 ......

    uj5u.com 2023-04-20 07:23:58 more
  • 理解函式指標和回呼函式

    理解 函式指標 指向函式的指標。比如: 理解函式指標的偽代碼 void (*p)(int type, char *data); // 定義一個函式指標p void func(int type, char *data); // 宣告一個函式func p = func; // 將指標p指向函式func ......

    uj5u.com 2023-04-20 07:23:52 more
  • Django筆記二十五之資料庫函式之日期函式

    本文首發于公眾號:Hunter后端 原文鏈接:Django筆記二十五之資料庫函式之日期函式 日期函式主要介紹兩個大類,Extract() 和 Trunc() Extract() 函式作用是提取日期,比如我們可以提取一個日期欄位的年份,月份,日等資料 Trunc() 的作用則是截取,比如 2022-0 ......

    uj5u.com 2023-04-20 07:23:45 more
  • 一天吃透JVM面試八股文

    什么是JVM? JVM,全稱Java Virtual Machine(Java虛擬機),是通過在實際的計算機上仿真模擬各種計算機功能來實作的。由一套位元組碼指令集、一組暫存器、一個堆疊、一個垃圾回收堆和一個存盤方法域等組成。JVM屏蔽了與作業系統平臺相關的資訊,使得Java程式只需要生成在Java虛擬機 ......

    uj5u.com 2023-04-20 07:23:31 more
  • 使用Java接入小程式訂閱訊息!

    更新完微信服務號的模板訊息之后,我又趕緊把微信小程式的訂閱訊息給實作了!之前我一直以為微信小程式也是要企業才能申請,沒想到小程式個人就能申請。 訊息推送平臺🔥推送下發【郵件】【短信】【微信服務號】【微信小程式】【企業微信】【釘釘】等訊息型別。 https://gitee.com/zhongfuch ......

    uj5u.com 2023-04-20 07:22:59 more
  • java -- 緩沖流、轉換流、序列化流

    緩沖流 緩沖流, 也叫高效流, 按照資料型別分類: 位元組緩沖流:BufferedInputStream,BufferedOutputStream 字符緩沖流:BufferedReader,BufferedWriter 緩沖流的基本原理,是在創建流物件時,會創建一個內置的默認大小的緩沖區陣列,通過緩沖 ......

    uj5u.com 2023-04-20 07:22:49 more
  • Java-SpringBoot-Range請求頭設定實作視頻分段傳輸

    老實說,人太懶了,現在基本都不喜歡寫筆記了,但是網上有關Range請求頭的文章都太水了 下面是抄的一段StackOverflow的代碼...自己大修改過的,寫的注釋挺全的,應該直接看得懂,就不解釋了 寫的不好...只是希望能給視頻網站開發的新手一點點幫助吧. 業務場景:視頻分段傳輸、視頻多段傳輸(理 ......

    uj5u.com 2023-04-20 07:22:42 more
  • Windows 10開發教程_編程入門自學教程_菜鳥教程-免費教程分享

    教程簡介 Windows 10開發入門教程 - 從簡單的步驟了解Windows 10開發,從基本到高級概念,包括簡介,UWP,第一個應用程式,商店,XAML控制元件,資料系結,XAML性能,自適應設計,自適應UI,自適應代碼,檔案管理,SQLite資料庫,應用程式到應用程式通信,應用程式本地化,應用程式 ......

    uj5u.com 2023-04-20 07:22:35 more