數據分析的python基底(4)建立數據分析的流程
今天要提醒自己的一件事是,「數據分析的使命是解決問題」,
有前輩說過,「解決問題,就要明確問題,追溯問題,大部分問題能描述就能解決」。
開始吧!
0、明確問題
下面的問題案例是,利用」醫院藥品銷售數據「,得出藥品銷售趨勢——
以及院長很關心以下指標:1)月均消費次數2)月均消費金額3)客單價,需要給他指標變動的答覆。
????????????????????????????????
這是一個很有實際意義的問題,而且涵蓋了數據分析指標的四個維度:變化、分布、對比、預測,
變化:指標隨時間的變動,表現為增幅(同比、環比等);
分布:指標在不同層次上的表現,包括地域分布(省、市、區縣、店/網點)、用戶群分布(年齡、性別、職業等)、產品分布(如動感地帶和全球通)等;對比:包括內部對比和外部對比,內部對比包括團隊對比(團隊A與B的單產對比、銷量對比等)、產品線對比(動感地帶和全球通的ARPU、用戶數、收入對比);外部對比主要是與市場環境和競爭者對比;這一部分和分布有重疊的地方,但分布更多用於找出好或壞的地方,而對比更偏重於找到好或壞的原因;預測:根據現有情況,估計下個分析時段的指標值。
(這個知識點來自 陳丹奕的文章,案例來自猴子的live 學習)
1、理解數據
導入數據到jupyter。這裡有個新招,沒有用pandas里慣用的read_excel讀入數據,而是選擇了pd.ExcelFile方法,帶參數dtype=object,統一將數據先以字元串類型讀入,之後看需求轉換類型。
#讀取Ecxcel數據,統一先按照字元串讀入,之後轉換fileNameStr=./朝陽醫院2018年銷售數據.xlsxxls = pd.ExcelFile(fileNameStr, dtype=object)salesDf = xls.parse(Sheet1,dtype=object)
為什麼這麼做呢?
我在有一次用Python處理基金收益時,使用read_excel,結果基金代碼導入後變成了int 格式,前面的0通通沒有了......當時我不太清楚怎麼處理,總之最後我寫了個(笨)函數把0加回去轉回string(object)類型。。。
無知過後在猴子這裡學到這個方法,使用它能夠提前避免一些麻煩。之後我們見機行事!(但純字元、無中文的csv格式我覺得直接read_csv就好了)
看,新導入的數據全部是object類型:
接下來了解數據大概面貌:
2、必要步驟:數據清洗
連《利用Python進行數據分析》的作者都在書里直接說,「在分析數據的整個過程中,有80%以上的時間花在數據清洗上」。這是一件基礎、重要、需要耐心細心的事。
數據清洗包括選擇數據範圍、對缺失值、異常值的處理,數據的類型轉變、排序、聚合轉化...我希望以後能好好總結一篇。
1)在數據源豐富的情況下,你可能不需要全部指標,那麼就選擇一部分子集:
用loc(行標籤、列標籤)或iloc(行號、列號)選取範圍,如 subSalesDf=salesDf.loc[0:,購葯時間:銷售數量],本案例中的指標我們都需要,就不篩選了。
2)數據重命名
原表有些指標以「買家」角度命名,在我們分析和彙報時用「賣家」角度更方便,可以改下名字:
#字典:舊列名和新列名對應關係colNameDict = {購葯時間:銷售時間}關於replace方法的參數inplace默認為False,實際上創建了一個原表的copy,原表不變inplace=True時,直接改動了原表salesDf.rename(columns = colNameDict,inplace=True)
3)缺失值/重複值處理
(首先缺失值是nan-特指浮點數的缺失或none-純粹的缺失,不是0)缺失值可以過濾(丟棄)或填充,填充我目前只知道 fillna(method=bfill/ffill),等明白多點再補充。
#刪除「銷售時間」,「社保卡號」含空值的行#參數how=any 表示任何一列有缺失值就刪除salesDfsalesDfsalesDfsalesDf=salesDf=salesDf.dropna(subset=[銷售時間,社保卡號],how=any)
案例中的指標本身有重複的可能,一時間找不到處理重複值的必要,不過等下定義指標會再處理。在有必要的情況下,比如查找學生ID有沒有重複,可以用 len(df.stuID.unique()) 和df.stuID.count() 比較,判斷是否有重複數據。若有就用 drop_duplicates() 刪除。
4)數據類型轉換
還記得一開始導入時把數據設置為統一類型了嗎,現在我們把需要做計算、排序的指標處理回數值:salesDf[銷售數量] = salesDf[銷售數量].astype(float),處理了三個指標:
還有」銷售時間「,形如」2018-01-01 星期五「。」星期五「在接下來的分析里沒什麼用,打算把它去掉。處理思路是利用中間的空格,用split把字元串分割,再將日期字元串轉成日期類型。
定義函數:分割銷售日期,保留」年-月-日「輸入:timeColSer 銷售時間,是Series類型數據輸出:分割後的時間,返回一個新的Seriesdef splitSaletime(timeColSer): timeList=[] for value in timeColSer: #例如2018-01-01 星期五,分割後為:2018-01-01 dateStr=value.split( )[0] timeList.append(dateStr) #將列錶轉行為一維數據Series類型 timeSer=pd.Series(timeList) return timeSer#對「銷售時間」使用函數timeSer=salesDf.loc[:,銷售時間]#將分割後的日期字元串儲存到dateSer,並替換表中原數據dateSer=splitSaletime(timeSer)salesDf.loc[:,銷售時間]=dateSer數據類型轉換:字元串轉換為日期#errors=coerce 如果原始數據不符合日期的格式,轉換後的值為空值NaT#format 是你原始數據中日期的格式salesDf.loc[:,銷售時間]=pd.to_datetime(salesDf.loc[:,銷售時間], format=%Y-%m-%d, errors=coerce)
轉化後的數據類型:
5)數據排序
by:按哪幾列排序ascending=True 表示降序ascending=False 表示升序#按銷售日期升序排列salesDf=salesDf.sort_values(by=[銷售時間,商品編碼], ascending=True)#重置索引(index):排序後索引被打亂,刪除原來的索引,新索引從0到N排序salesDf=salesDf.reset_index(drop=True)salesDf.head()
6)異常值處理
什麼是異常值常常需要結合實際業務判斷,比如案例里「銷售數量」、」金額「不應該小於0。它們都是數值型變數,可以通過describe()查看基本統計量(類別型變數用 info()查看基本情況)
確實存在異常值。篩選出正常值:salesDf=salesDf[(salesDf[銷售數量])>0 & (salesDf[應收金額]>0)]
至此數據基本清洗完畢,進入探究結果的下一步~
3、構造模型
1)構造指標
回憶一下院長的任務:分析以下指標,並給出變化趨勢。
- 月均消費次數
- 月均消費金額
- 客單價
不同的業務有不同的指標,定義指標是為了衡量業務。如果說」沒有明確問題就不能解決問題「,那麼」無法衡量數據就無法增長數據「,想想公司定的KPI~
月均消費次數=月總消費次數/天數,可是分析重複值時我們注意到,社保卡號、商品名稱、銷售時間都存在重複可能,就是一個人一天里買了多次葯。
這裡定義」同一天內,同一個人發生的所有消費算作一次消費「,那麼需刪除」銷售時間「和」銷售時間「的重複值:
kpi1_Df=salesDf.drop_duplicates(subset=[銷售時間, 社保卡號])#總消費次數:totalI=kpi1_Df.shape[0]#第1步:按銷售時間升序排序kpi1_Df=kpi1_Df.sort_values(by=銷售時間,ascending=True)#重置索引kpi1_Df=kpi1_Df.reset_index(drop=True)#第2步:獲取時間範圍#最小時間值startTime=kpi1_Df.loc[0,銷售時間]#最大時間值endTime=kpi1_Df.loc[totalI-1,銷售時間]#第3步:計算月份數#天數daysI=(endTime-startTime).days#月份數: 運算符「//」表示取整除 #返回商的整數部分,例如9//2 輸出結果是4monthsI=daysI//30print(月份數:,monthsI)
月份數: 6
#指標1:月均消費次數 = 總消費次數 / 月份數kpi1_I=totalI // monthsIprint(指標1:月均消費次數=,kpi1_I)#指標2:月均消費金額 = 總消費金額 / 月份數totalMoneyF=salesDf.loc[:,實收金額].sum()monthMoneyF=totalMoneyF / monthsIprint(指標2:月均消費金額=,monthMoneyF)#指標3:客單價 = 總消費金額 / 總消費次數pct=totalMoneyF / totalIprint(指標3:客單價:,pct)
指標1:月均消費次數= 890
指標2:月均消費金額= 50668.351666666305
指標3:客單價=56.9094178210404
2)消費趨勢
這部分用到pandas包里的高級功能,應該是「時間序列」吧,這一章還沒有讀過。。先跟著猴子的思路走,之後補!
#在分析前,先把數據複製到新表,防止對之前的乾淨數據造成影響groupDf=salesDf#第1步:重置行索引(index)為銷售時間所在列的值groupDf.index=groupDf[銷售時間]groupDf.head()
#第2步:分組gb=groupDf.groupby(groupDf.index.month)#第3步:應用函數,計算每個月的消費總額mounthDf=gb.sum()mounthDf
待續...
推薦閱讀: