
1 讀取數(shù)據(jù)
import pandas as pd
import numpy as np
df = pd.read_csv(r'alldata(隨機抽15萬樣本).csv',low_memory=False)
df['時間戳']= pd.to_datetime(df['時間戳'])
df['月度'] = df['時間戳'].dt.year.astype(str)+'/'+df['時間戳'].dt.month.astype(str)
df['月度'] = pd.to_datetime(df['月度'],format='%Y/%M').dt.strftime('%Y-%M')
df['年度'] = df['時間戳'].dt.year
df['年度'] = df['年度'].astype(str)
df['日度'] = df['時間戳'].dt.date
df

1.2 每日不同產(chǎn)品線的同期數(shù)據(jù)
df_cateperday_2022 = (df.set_index('時間戳').query("年度=='2022'")
.groupby('產(chǎn)品').用戶.resample('D')
.count().to_frame('2022')
.reset_index()
.assign(月 = lambda x:x['時間戳'].dt.month
,日度 = lambda x:(x['時間戳'].dt.date).astype(str)
,日期 = lambda x:x['日度'].apply(lambda x:x.split('2022-')[1])
)
)[['月','產(chǎn)品','日期','2022']]
df_cateperday_2021 = (df.set_index('時間戳').query("年度=='2021'")
.groupby('產(chǎn)品').用戶.resample('D')
.count().to_frame('2021')
.reset_index()
.assign(月 = lambda x:x['時間戳'].dt.month
,日度 = lambda x:(x['時間戳'].dt.date).astype(str)
,日期 = lambda x:x['日度'].apply(lambda x:x.split('2021-')[1])
)
)[['月','產(chǎn)品','日期','2021']]
mer_result_li = pd.merge(df_cateperday_2021,df_cateperday_2022,how='outer')
mer_result_li['2021'] = mer_result_li['2021'].fillna(0)
mer_result_li

1.2.1 驗證一下產(chǎn)品A在2021年和2022年1月2日中的數(shù)據(jù)
len(df[(df['時間戳']>='2021-01-02')&(df['時間戳']<'2021-01-03')].query("產(chǎn)品=='A'")),len(df[(df['時間戳']>='2022-01-02')&(df['時間戳']<'2022-01-03')].query("產(chǎn)品=='A'"))
Out:(28, 17)
1.3 構(gòu)造一個新的產(chǎn)品數(shù)據(jù),其類型為:“所有數(shù)據(jù)”
all_li_2021 = (df.set_index('時間戳').query("年度=='2021'")
.用戶.resample('D')
.count().to_frame('2021')
.reset_index()
.assign(月 = lambda x:x['時間戳'].dt.month
,產(chǎn)品 = '所有數(shù)據(jù)'
,日度 = lambda x:(x['時間戳'].dt.date).astype(str)
,日期 = lambda x:x['日度'].apply(lambda x:x.split('2021-')[1])
)
)[['月','產(chǎn)品','日期','2021']]
all_li_2022 = (df.set_index('時間戳').query("年度=='2022'")
.用戶.resample('D')
.count().to_frame('2022')
.reset_index()
.assign(月 = lambda x:x['時間戳'].dt.month
,產(chǎn)品 = '所有數(shù)據(jù)'
,日度 = lambda x:(x['時間戳'].dt.date).astype(str)
,日期 = lambda x:x['日度'].apply(lambda x:x.split('2022-')[1])
)
)[['月','產(chǎn)品','日期','2022']]
All_li = pd.merge(all_li_2021,all_li_2022,how='outer')
All_li['2021'] = All_li['2021'].fillna(0)
All_li
注意將2021年的缺失值補為0,2022年的不需要,否則做折線圖的時候會有很長一段為0的數(shù)據(jù),影響視覺效果。

1.3.1 驗證1月1日的數(shù)據(jù)
len(df[(df['時間戳']>='2021-01-01')&(df['時間戳']<'2021-01-02')]),len(df[(df['時間戳']>='2022-01-01')&(df['時間戳']<'2022-01-02')])
[Out]:(37, 32)
1.4 拼接兩個模塊的數(shù)據(jù)
concat_apply_counts = (pd.concat([mer_result_li,All_li])#
.assign(aa = lambda x:np.where(x['日期']<'04-29',x['2022'].fillna(0),np.NaN))
.drop(labels='2022',axis=1).rename(columns={'aa':'2022'})
)#.to_clipboard()
concat_apply_counts
注意中間有個np.where的方法,當日期小于4月29日時,2022年的那一列填補缺失值為0,否則記為空值。

1.4.1 優(yōu)化小于日期的功能
每次運行程序盡量不要手動改日期,形成通用的數(shù)據(jù)處理流程應根據(jù)這張表的時間戳字段的最新日期作為數(shù)值,即數(shù)據(jù)更新到哪兒了。
查看新時間戳

+pd.DateOffset(days=1)可以使日期加上一天

str轉(zhuǎn)成字符串

最后取出相應的內(nèi)容

concat_apply_counts = (pd.concat([mer_result_li,All_li])#
.assign(aa = lambda x:np.where(x['日期']<str(df['時間戳'].max()+pd.DateOffset(days=1))[5:10],x['2022'].fillna(0),np.NaN))
.drop(labels='2022',axis=1).rename(columns={'aa':'2022'})
)#.to_clipboard()
concat_apply_counts
這時,時間戳字段就不能用lambda函數(shù)里面的x了,因為它代表了pd.concat中的那張表,因此得使用最開始的那張df表。
2 構(gòu)造每日不同產(chǎn)品的用戶數(shù)量(中間有大坑)
假設aaa用戶2021年1月1日,A產(chǎn)品,20次記錄。B產(chǎn)品,0次記錄。倘若用resample.count的方法,用戶數(shù)本應該是1個,但會記為2個。如果用resample.sum也是不行的。而且,當2021年1月2日,aaa用戶沒有記錄時,resample模塊會自動生成日期,并使得相應的數(shù)據(jù)等于0,那么第二次groupby的時候,一樣會記錄一次數(shù)據(jù)。
面對這樣的情形,resample就不合適了。需要通過時間戳構(gòu)造一列日期,所以第一次讀取數(shù)據(jù)時將日期做了處理。那么,沒有發(fā)生的數(shù)據(jù)就不會多出日期,并且對應數(shù)值為0的情況。
2.1 每個產(chǎn)品線的用戶數(shù)量
df_organ_cate_2022 = (df.query("年度=='2022'").groupby(['日度','用戶','產(chǎn)品']).日度.count().to_frame('次數(shù)').reset_index()
.groupby(['日度','產(chǎn)品']).用戶.count().to_frame('2022點數(shù)').reset_index()
.assign(日期 = lambda x:pd.to_datetime(x['日度'])
,月 = lambda x:x['日期'].dt.month
)
)[['月','產(chǎn)品','日期','2022點數(shù)']]
df_organ_cate_2022['日期'] = df_organ_cate_2022['日期'].astype(str).apply(lambda x:x.split('2022-')[1])
df_organ_cate_2021 = (df.query("年度=='2021'").groupby(['日度','用戶','產(chǎn)品']).日度.count().to_frame('次數(shù)').reset_index()
.groupby(['日度','產(chǎn)品']).用戶.count().to_frame('2021點數(shù)').reset_index()
.assign(日期 = lambda x:pd.to_datetime(x['日度'])
,月 = lambda x:x['日期'].dt.month
)
)[['月','產(chǎn)品','日期','2021點數(shù)']]
df_organ_cate_2021['日期'] = df_organ_cate_2021['日期'].astype(str).apply(lambda x:x.split('2021-')[1])
mer_result_cate = pd.merge(df_organ_cate_2021,df_organ_cate_2022,how='outer')
mer_result_cate['2021點數(shù)'] = mer_result_cate['2021點數(shù)'].fillna(0)
mer_result_cate

2.2 所有產(chǎn)品線的用戶數(shù)量
df_organ_all_2022 = (df.query("年度=='2022'").groupby(['日度','用戶']).日度.count().to_frame('次數(shù)').reset_index()
.groupby(['日度']).用戶.count().to_frame('2022點數(shù)').reset_index()
.assign(日期 = lambda x:pd.to_datetime(x['日度'])
,月 = lambda x:x['日期'].dt.month
,產(chǎn)品 = '所有數(shù)據(jù)'
#,年度 =
)
)[['月','產(chǎn)品','日期','2022點數(shù)']]
df_organ_all_2022['日期'] = df_organ_all_2022['日期'].astype(str).apply(lambda x:x.split('2022-')[1])
df_organ_all_2021 = (df.query("年度=='2021'").groupby(['日度','用戶']).日度.count().to_frame('次數(shù)').reset_index()
.groupby(['日度']).用戶.count().to_frame('2021點數(shù)').reset_index()
.assign(日期 = lambda x:pd.to_datetime(x['日度'])
,月 = lambda x:x['日期'].dt.month
,產(chǎn)品 = '所有數(shù)據(jù)'
#,年度 =
)
)[['月','產(chǎn)品','日期','2021點數(shù)']]
df_organ_all_2021['日期'] = df_organ_all_2021['日期'].astype(str).apply(lambda x:x.split('2021-')[1])
mer_result_all = pd.merge(df_organ_all_2021,df_organ_all_2022,how='outer')
mer_result_all['2021點數(shù)'] = mer_result_all['2021點數(shù)'].fillna(0)
mer_result_all

2.3 合并一下
concat_apply_members = (pd.concat([mer_result_cate,mer_result_all])#
.assign(aa = lambda x:np.where(x['日期']<'04-29',x['2022點數(shù)'].fillna(0),np.NaN))
.drop(labels='2022點數(shù)',axis=1).rename(columns={'aa':'2022點數(shù)'})
)
concat_apply_members

2.4 驗證1月1日A產(chǎn)品的用戶量
len(df[(df['時間戳']>='2021-01-01')&(df['時間戳']<'2021-01-02')].query("產(chǎn)品=='A'")['用戶'].unique()),len(df[(df['時間戳']>='2022-01-01')&(df['時間戳']<'2022-01-02')].query("產(chǎn)品=='A'")['用戶'].unique())
[Out]:(14, 8)
2.5 用每日數(shù)據(jù)量左連接每日用戶量,并粘貼到excel中
(pd.merge(concat_apply_counts,concat_apply_members,how='left')
.assign(aa2021 = lambda x:x['2021點數(shù)'].fillna(0)
,aa2022 = lambda x:np.where(x['日期']<'04-29',x['2022點數(shù)'].fillna(0),np.NaN)
)
.drop(labels=['2021點數(shù)','2022點數(shù)'],axis=1)
.rename(columns={'aa2021':'2021點數(shù)','aa2022':'2022點數(shù)'})
).to_clipboard(index=None,excel=True)#to_clipboard相當于復制,打開excel粘貼即可將數(shù)據(jù)傳入excel內(nèi)
2.6 嘗試寫一個類
默認使用2022年作為最新數(shù)據(jù),同期年份有所保留,是為了方便測試其他年份的數(shù)據(jù)
import pandas as pd
import numpy as np
df = pd.read_csv(r'alldata(隨機抽15萬樣本).csv',low_memory=False)
df['時間戳']= pd.to_datetime(df['時間戳'])
df['月度'] = df['時間戳'].dt.year.astype(str)+'/'+df['時間戳'].dt.month.astype(str)
df['月度'] = pd.to_datetime(df['月度'],format='%Y/%M').dt.strftime('%Y-%M')
df['年度'] = df['時間戳'].dt.year
df['年度'] = df['年度'].astype(str)
df['日度'] = df['時間戳'].dt.date
class Streaming_perday:
def __init__(self,data,nowyear='2022',lastyear=None):
self.data = data
self.nowyear = nowyear
self.nowformat = '%s點數(shù)'%self.nowyear
self.lastyear = lastyear
self.lastformat = '%s點數(shù)'%self.lastyear
def perday_num(self):
df_cateperday_2022 = (self.data.set_index('時間戳').query("年度=='%s'"%self.nowyear)
.groupby('產(chǎn)品').用戶.resample('D')
.count().to_frame('%s'%self.nowyear)
.reset_index()
.assign(月 = lambda x:x['時間戳'].dt.month
,日度 = lambda x:(x['時間戳'].dt.date).astype(str)
,日期 = lambda x:x['日度'].apply(lambda x:x.split('%s-'%self.nowyear)[1])
)
)[['月','產(chǎn)品','日期','%s'%self.nowyear]]
df_cateperday_2021 = (self.data.set_index('時間戳').query("年度=='%s'"%self.lastyear)
.groupby('產(chǎn)品').用戶.resample('D')
.count().to_frame('%s'%self.lastyear)
.reset_index()
.assign(月 = lambda x:x['時間戳'].dt.month
,日度 = lambda x:(x['時間戳'].dt.date).astype(str)
,日期 = lambda x:x['日度'].apply(lambda x:x.split('%s-'%self.lastyear)[1])
)
)[['月','產(chǎn)品','日期','%s'%self.lastyear]]
mer_result_li = pd.merge(df_cateperday_2021,df_cateperday_2022,how='outer')
mer_result_li['%s'%self.lastyear] = mer_result_li['%s'%self.lastyear].fillna(0)
#所有數(shù)據(jù)的resample
all_li_2021 = (self.data.set_index('時間戳').query("年度=='%s'"%self.lastyear)
.用戶.resample('D')
.count().to_frame('%s'%self.lastyear)
.reset_index()
.assign(月 = lambda x:x['時間戳'].dt.month
,產(chǎn)品 = '所有數(shù)據(jù)'
,日度 = lambda x:(x['時間戳'].dt.date).astype(str)
,日期 = lambda x:x['日度'].apply(lambda x:x.split('%s-'%self.lastyear)[1])
)
)[['月','產(chǎn)品','日期','%s'%self.lastyear]]
all_li_2022 = (self.data.set_index('時間戳').query("年度=='%s'"%self.nowyear)
.產(chǎn)品.resample('D')
.count().to_frame('%s'%self.nowyear)
.reset_index()
.assign(月 = lambda x:x['時間戳'].dt.month
,產(chǎn)品 = '所有數(shù)據(jù)'
,日度 = lambda x:(x['時間戳'].dt.date).astype(str)
,日期 = lambda x:x['日度'].apply(lambda x:x.split('%s-'%self.nowyear)[1])
)
)[['月','產(chǎn)品','日期','%s'%self.nowyear]]
All_li = pd.merge(all_li_2021,all_li_2022,how='outer')
All_li['%s'%self.lastyear] = All_li['%s'%self.lastyear].fillna(0)
concat_apply_counts = (pd.concat([mer_result_li,All_li])#
.assign(aa = lambda x:np.where(x['日期']<str(self.data['時間戳'].max()+pd.DateOffset(days=1))[5:10]#日期小于最大診斷時間的第二天,切割字符串
,x['%s'%self.nowyear].fillna(0),np.NaN)
)
.drop(labels='%s'%self.nowyear,axis=1).rename(columns={'aa':'%s'%self.nowyear})
)
return concat_apply_counts
def perday_num_organ(self):
df_organ_all_2022 = (self.data.query("年度=='%s'"%self.nowyear).groupby(['日度','用戶']).日度.count().to_frame('次數(shù)').reset_index()
.groupby(['日度']).用戶.count().to_frame(self.nowformat).reset_index()
.assign(日期 = lambda x:pd.to_datetime(x['日度'])
,月 = lambda x:x['日期'].dt.month
,產(chǎn)品 = '所有數(shù)據(jù)'
)
)[['月','產(chǎn)品','日期',self.nowformat]]
df_organ_all_2022['日期'] = df_organ_all_2022['日期'].astype(str).apply(lambda x:x.split('%s-'%self.nowyear)[1])
df_organ_all_2021 = (self.data.query("年度=='%s'"%self.lastyear).groupby(['日度','用戶']).日度.count().to_frame('次數(shù)').reset_index()
.groupby(['日度']).用戶.count().to_frame(self.lastformat).reset_index()
.assign(日期 = lambda x:pd.to_datetime(x['日度'])
,月 = lambda x:x['日期'].dt.month
,產(chǎn)品 = '所有數(shù)據(jù)'
#,年度 =
)
)[['月','產(chǎn)品','日期',self.lastformat]]
df_organ_all_2021['日期'] = df_organ_all_2021['日期'].astype(str).apply(lambda x:x.split('%s-'%self.lastyear)[1])
df_organ_cate_2022 = (self.data.query("年度=='%s'"%self.nowyear).groupby(['日度','用戶','產(chǎn)品']).日度.count().to_frame('次數(shù)').reset_index()
.groupby(['日度','產(chǎn)品']).用戶.count().to_frame(self.nowformat).reset_index()
.assign(日期 = lambda x:pd.to_datetime(x['日度'])
,月 = lambda x:x['日期'].dt.month
)
)[['月','產(chǎn)品','日期',self.nowformat]]
df_organ_cate_2022['日期'] = df_organ_cate_2022['日期'].astype(str).apply(lambda x:x.split('%s-'%self.nowyear)[1])
df_organ_cate_2021 = (self.data.query("年度=='%s'"%self.lastyear).groupby(['日度','用戶','產(chǎn)品']).日度.count().to_frame('次數(shù)').reset_index()
.groupby(['日度','產(chǎn)品']).用戶.count().to_frame(self.lastformat).reset_index()
.assign(日期 = lambda x:pd.to_datetime(x['日度'])
,月 = lambda x:x['日期'].dt.month
)
)[['月','產(chǎn)品','日期',self.lastformat]]
df_organ_cate_2021['日期'] = df_organ_cate_2021['日期'].astype(str).apply(lambda x:x.split('%s-'%self.lastyear)[1])
mer_result_cate = pd.merge(df_organ_cate_2021,df_organ_cate_2022,how='outer')
mer_result_cate[self.lastformat] = mer_result_cate[self.lastformat].fillna(0)
mer_result_all = pd.merge(df_organ_all_2021,df_organ_all_2022,how='outer')
mer_result_all[self.lastformat] = mer_result_all[self.lastformat].fillna(0)
concat_apply_members = (pd.concat([mer_result_cate,mer_result_all])#
.assign(aa = lambda x:np.where(x['日期']<str(self.data['時間戳'].max()+pd.DateOffset(days=1))[5:10]
,x[self.nowformat].fillna(0)
,np.NaN)
)#注意選擇時間
.drop(labels=self.nowformat,axis=1).rename(columns={'aa':self.nowformat})
)
return concat_apply_members
def merge_result(self):
mer_result = (
pd.merge(self.perday_num(),self.perday_num_organ(),how='outer')
.assign(aa2021 = lambda x:x[self.lastformat].fillna(0)
,aa2022 = lambda x:np.where(
x['日期']<str(self.data['時間戳'].max()+pd.DateOffset(days=1))[5:10]
,x[self.nowformat].fillna(0)
,np.NaN
)
)
.drop(labels=[self.lastformat,self.nowformat],axis=1)
.rename(columns={'aa2021':self.lastformat,'aa2022':self.nowformat})
)
return mer_result#,mer_result.to_clipboard(index=None,excel=True),'已將數(shù)據(jù)結(jié)果進行復制,請移至excel中進行粘貼....'
# stream = Streaming_perday(data=df,lastyear='2021')
# stream.merge_result()
if __name__=="__main__":
stream = Streaming_perday(data=df,lastyear='2021')
print(stream.merge_result())
【Out】: 月 產(chǎn)品 日期 2021 2022 2021點數(shù) 2022點數(shù)
0 1 A 01-01 21.0 21.0 14.0 8.0
1 1 A 01-02 28.0 17.0 19.0 13.0
2 1 A 01-03 28.0 22.0 18.0 16.0
3 1 A 01-04 46.0 41.0 31.0 24.0
4 1 A 01-05 48.0 46.0 26.0 24.0
... .. ... ... ... ... ... ...
2273 12 所有數(shù)據(jù) 12-27 44.0 NaN 22.0 NaN
2274 12 所有數(shù)據(jù) 12-28 43.0 NaN 25.0 NaN
2275 12 所有數(shù)據(jù) 12-29 36.0 NaN 21.0 NaN
2276 12 所有數(shù)據(jù) 12-30 47.0 NaN 22.0 NaN
2277 12 所有數(shù)據(jù) 12-31 58.0 NaN 30.0 NaN
3 搭建動態(tài)看板

注意兩點即可:
1.更新數(shù)據(jù)源

2.右鍵切片器選擇報表鏈接,勾選透視表

3.選項功能添加自定義排序,使得產(chǎn)品切片器按鈕以對應數(shù)據(jù)量的大小來進行排序。

4.美化圖(略...)
5.從上圖不難發(fā)現(xiàn),從3月后半段開始,數(shù)據(jù)迅速下滑,同期下降30%+。然而根據(jù)3月的數(shù)據(jù)報告顯示,3月同期下降僅為10%,“10%”的指標有相當大的迷惑性。搭建每日的動態(tài)看板,及時向業(yè)務部反應情況,就能很好地彌補月匯報滯后性的不足。