python 数据分析 实际案例_python实战案例:超市营业额数据分析
實戰是學習的最好途徑,效率最高,本文不是很長,通過小小的練習,讓大家綜合運用基礎知識,加深印象鞏固記憶。
一、讀入數據,了解數據
本數據隨機生成的假數據,讀者可以自己造,也可以通過下方鏈接下載,或者后臺回復“超市營業額”獲取:
鏈接:https://pan.baidu.com/s/1OIOwBdBZydgRf5U72Gh_vg
提取碼:vedz
讀入數據
import random import numpy as np import pandas as pd import matplotlib.pyplot as plt # 生成營業額400-4000,生成400個隨機數 # np.random.randint(400,4000,400) df=pd.read_excel("超市營業額數據.xlsx") df.head(10)了解數據
通過.info() 和 .describe()方法分別查看數據大概是什么樣的
df.info() --------------------------------------------------------------------- out: <class 'pandas.core.frame.DataFrame'> RangeIndex: 256 entries, 0 to 255 Data columns (total 6 columns): 工號 256 non-null int64 姓名 256 non-null object 日期 256 non-null datetime64[ns] 時段 256 non-null object 交易額 242 non-null float64 柜臺 256 non-null object dtypes: datetime64[ns](1), float64(1), int64(1), object(3) memory usage: 12.1+ KB數據總共256個觀測,6個變量/特征,工號是整型,日期是日期型,交易額是浮點型,其他是字符型數據。“交易額”有缺失數據。
#將工號的數據類型由原來是整型調整為字符型df['工號']=df["工號"].apply(lambda x:str(x)) df.info() --------------------------------------------------------------------- out: <class 'pandas.core.frame.DataFrame'> RangeIndex: 256 entries, 0 to 255 Data columns (total 6 columns): 工號 256 non-null object 姓名 256 non-null object 日期 256 non-null datetime64[ns] 時段 256 non-null object 交易額 242 non-null float64 柜臺 256 non-null object dtypes: datetime64[ns](1), float64(1), object(4) memory usage: 12.1+ KB從統計量角度,可以看到數值型的變量(交易額)的最大值、最小值、均值、四分位值,標準差的五值分布。均值是2123.88,最大為3988,最小是404,中位數是2239.5。
df.describe() --------------------------------------------------------------------- out:交易額 count 242.000000 mean 2123.884298 std 1033.596041 min 404.000000 25% 1211.500000 50% 2239.500000 75% 3023.250000 max 3988.000000題目1:
刪除重復數據,把缺失的交易額使用每個員工自己所有交易額的中值進行填充,把小于500的交易額統一改為500,大于3000的交易額改為3000,修改后的數據保存為文件“數據調整結果.xlsx”,文件結構與“超市營業額數據.xlsx”相同。
# 查看重復數據 df[df.duplicated()] # 刪除重復數據 df.drop_duplicates()重復的數據如下:
for i in df[df["交易額"].isnull()].index:#循環遍歷交易額有缺失值的索引#取到交易額有缺失值的索引,根據索引找到人名,用這些人對應的交易額中位數填充df.loc[i,"交易額"]=round(df.loc[df.姓名==df.loc[i,"姓名"],"交易額"].median()) --------------------------------------------------------------------- df.loc[df["交易額"]<500,"交易額"]=500 df.loc[df["交易額"]>3000,"交易額"]=3000解析:
df.loc[df.姓名==df.loc[i,"姓名"],"交易額"]:取有營業額缺失的索引對應的人的營業額
所有營業額的缺失值已經被填補 df.info() --------------------------------------------------------------------- out: <class 'pandas.core.frame.DataFrame'> RangeIndex: 256 entries, 0 to 255 Data columns (total 6 columns): 工號 256 non-null object 姓名 256 non-null object 日期 256 non-null datetime64[ns] 時段 256 non-null object 交易額 256 non-null float64 柜臺 256 non-null object dtypes: datetime64[ns](1), float64(1), object(4) memory usage: 12.1+ KB驗證:
df[df["交易額"].isnull()].index --------------------------------------------------------------------- out: Int64Index([6, 29, 80, 113, 127, 149, 152, 175, 187, 194, 202, 228, 232, 254], dtype='int64')索引6對應的人為“錢八”,他的所有營業額的中位數是:
round(df.loc[df.姓名=="錢八","交易額"].median()) --------------------------------------------------------------------- out: 1536處理后的數據如下:
保存數據:
df.to_excel("數據調整結果.xlsx",index=False)題目2:
查看單日交易總額最小的3天的交易數據,并查看這三天是周幾,程序運行后直接輸出這些結果。
df2=df.groupby(by="日期",as_index=False).agg({"交易額":"sum"}).nsmallest(3,["日期",'交易額']) df2 --------------------------------------------------------------------- out:日期 交易額 0 2019-03-01 13809.0 1 2019-03-02 19364.0 2 2019-03-03 16821.0 pd.to_datetime(df2["日期"]).dt.weekday_name ----------------------------------------------------------------------- out: 0 Friday 1 Saturday 2 Sunday Name: 日期, dtype: object解析:
df.groupby(by="日期",as_index=False).agg({"交易額":"sum"}):根據日期分類匯總,按交易額求和匯總
nsmallest:傳入保留最小的前幾位n和保留的列名。
題目3:
把所有員工的工號前面增加一位數字,增加的數字和原工號最后一位相同,把修改后的數據寫入新文件“超市營業額2_修改工號.xlsx”。例如,工號1001變為11001,1003變為31003
from copy import deepcopy #深拷貝 df3=deepcopy(df) fx=lambda x:str(x)[-1]+str(x) df3['gh2']=df[['工號']].applymap(fx) df3 --------------------------------------------------------------------- out:解析:
1、lambda x:str(x)[-1]+str(x):定義lambda表達式,用于參數x(x轉化為字符串后切片取末位,然后再拼接一個轉為字符串的x)
2、df[['工號']].applymap(fx):applymap()函數作用對象為DataFrame,調用定義的lambda表達書,逐個作用在df[['工號']]的工號上。 當然還可以用apply()函數和map()函數,變換作用對象即可:
map()和apply()作用對象為Series。
df3['gh1']=df['工號'].map(fx) df3['gh3']=df['工號'].apply(fx) --------------------------------------------------------------------- out: 保存數據到超市營業額2_修改工號.xlsxdf3.to_excel("超市營業額2_修改工號.xlsx",index=False)額外補充:
1、深拷貝和淺拷貝通俗理解
a是自定義的列表,b是copy(a),c是deepcopy(a),改變列表a中的值,b會隨之改變,c還是原來的a。
2、==和is的區別:
python對象三要素:id(身份標識)、type(數據類型)、value(值)
==是比較操作,用來判斷兩個對象的value(值)是否相等
is是同一性運算符,判斷比較兩個對象的唯一身份id
題目4:
把每個員工的交易數據寫入文件“各員工數據.xlsx”,每個員工的數據占一個worksheet,結構和“超市營業額2.xlsx”一樣,并以員工姓名作為worksheet的標題。
writer=pd.ExcelWriter("各員工數據.xlsx") names=set(df['姓名']) names --------------------------------------------------------------------- out: {'周七', '張三', '李四', '王五', '趙六', '錢八'}for name in names:dff=df[df['姓名']==name]dff.to_excel(writer,sheet_name=name,index=False) writer.save() --------------------------------------------------------------------- out:最終結果如下(前面所有生成的文件和本題產出的excel文件):
題目5:
查看日期尾數為6的數據前12行,輸出這些結果
df[df['日期'].map(lambda x:x.strftime("%Y-%m-%d").endswith("6"))][:12] --------------------------------------------------------------------- out:工號 姓名 日期 時段 交易額 柜臺 44 1002 李四 2019-03-06 9:00-14:00 799.0 化妝品 45 1005 周七 2019-03-06 14:00-21:00 2726.0 化妝品 46 1002 李四 2019-03-06 9:00-14:00 1519.0 食品 47 1003 王五 2019-03-06 14:00-21:00 3000.0 食品 48 1003 王五 2019-03-06 9:00-14:00 2343.0 日用品 49 1005 周七 2019-03-06 14:00-21:00 3000.0 日用品 50 1003 王五 2019-03-06 9:00-14:00 2293.0 蔬菜水果 51 1004 趙六 2019-03-06 14:00-21:00 1970.0 蔬菜水果 126 1002 李四 2019-03-16 9:00-14:00 3000.0 化妝品 127 1003 王五 2019-03-16 14:00-21:00 2428.0 化妝品 128 1003 王五 2019-03-16 9:00-14:00 2732.0 食品 129 1001 張三 2019-03-16 14:00-21:00 1650.0 食品方法二:用datetime模塊
from datetime import datetime df[df['日期'].map(lambda x:str(datetime.date(x)).endswith('16'))][:12] --------------------------------------------------------------------- out:工號 姓名 日期 時段 交易額 柜臺 126 1002 李四 2019-03-16 9:00-14:00 3000.0 化妝品 127 1003 王五 2019-03-16 14:00-21:00 2428.0 化妝品 128 1003 王五 2019-03-16 9:00-14:00 2732.0 食品 129 1001 張三 2019-03-16 14:00-21:00 1650.0 食品 130 1002 李四 2019-03-16 9:00-14:00 2823.0 日用品 131 1003 王五 2019-03-16 14:00-21:00 2857.0 日用品 132 1004 趙六 2019-03-16 9:00-14:00 511.0 蔬菜水果 133 1005 周七 2019-03-16 14:00-21:00 2658.0 蔬菜水果解析:
思路都是一樣的,首先定義lambda表達式(也可以自定義函數),對其字符化處理后調用字符處理函數endswith()函數判斷以什么結尾,方法一直接用格式化時間,方法二調用datetime模塊datetime.date,將日期時間類型轉化為日期型后,在轉化為字符串。
題目6:
計算張三每天交易總額的增幅,也就是每天交易總額減去前一天的交易總額,程序運行后輸出前5天的結果
df[df['姓名']=="張三"].groupby(by='日期').交易額.sum() #張三每天總的交易額 --------------------------------------------------------------------- out: 日期 2019-03-01 1664.0 2019-03-02 680.0 2019-03-04 1823.0 2019-03-07 2352.0 2019-03-09 2522.0 2019-03-11 3000.0 2019-03-12 592.0 2019-03-14 2676.0 2019-03-16 1650.0 2019-03-18 1266.0 2019-03-19 1414.0 2019-03-21 3000.0 2019-03-22 3000.0 2019-03-24 1942.0 2019-03-26 1725.0 2019-03-28 518.0 2019-03-29 2651.0 2019-03-31 3000.0 Name: 交易額, dtype: float64增幅利用diff()函數,簡單粗暴:
df[df['姓名']=="張三"].groupby(by='日期').交易額.sum().diff()[:5] --------------------------------------------------------------------- out: 日期 2019-03-01 NaN 2019-03-02 -984.0 2019-03-04 1143.0 2019-03-07 529.0 2019-03-09 170.0 Name: 交易額, dtype: float64題目7:
繪制折線圖展示一個月內各柜臺營業額每天變化趨勢,保存為“1.png”,設置dpi為200
## 設置字符集,防止中文亂碼 import matplotlib as mpl mpl.rcParams['font.sans-serif']=[u'simHei'] mpl.rcParams['axes.unicode_minus']=Falsedf7=df.loc[:,['日期','柜臺','交易額']].groupby(by=['日期','柜臺'],as_index=False).sum() df7.pivot(index='日期',columns='柜臺',values='交易額').plot() plt.title("每天各柜臺營業額的變化") plt.legend(loc='best') plt.xticks(rotation=5) plt.savefig("1.jpg",dpi=200)題目8:
繪制餅狀圖展示該月各柜臺營業額在交易總額中的占比,保存為“2.png”,設置dpi為200
df8.plot(x='柜臺',y='交易額',kind='pie',labels=df8['柜臺'].values) plt.legend(loc=(1,0.5)) plt.title("各柜臺營業額占比圖") plt.savefig("2.png",dpi=200)題目9:
把銷售總額低于5萬的員工工號和姓名寫入“業績差的員工.txt”文件,每行一個員工信息,工號,姓名和交易額之間使用英文逗號分隔
df9=df.groupby(by=["姓名","工號"],as_index=False).sum() df99=df9[df9['交易額']<=50000] df99 --------------------------------------------------------------------- out:姓名 工號 交易額 1 張三 1001 35475.0 5 錢八 1006 37115.0with open("業績差的員工.txt","w+",encoding="utf-8") as fp:for name in df99['姓名'].values:gh=df99[df99['姓名']==name].工號.values[0]jye=df99[df99['姓名']==name].交易額.values[0]fp.write(str(gh)+','+name+','+str(jye)+'n')輸出結果如下圖:
題目10:
繪制柱狀圖展示每個員工在不同柜臺上的交易總額,結果類似于下圖,保存為“3.png”,設置dpi為200
方法一:DataFrame.pivot_table() df10=df.pivot_table(index='姓名',columns='柜臺',values='交易額',aggfunc="sum").apply(round) df10 方法二:Pandas.crosstab() df10=pd.crosstab(df.姓名,df.柜臺,df.交易額,aggfunc="sum").apply(round) df10 df10.plot(kind="bar") plt.xlabel("員工業績分布") plt.legend(loc="upper right") plt.savefig("3.jpg",dpi=200)本題重點:
☆☆☆☆☆☆☆DataFrame透視表功能 VS Pandas的交叉表功能☆☆☆☆☆☆☆
1、df.pivot_table(index='姓名',columns='柜臺',values='交易額',aggfunc="sum")
pivot_table()透視表功能,作用對象是DataFrame,參數index、columns、values,aggfunc。
可以通過help(pivot_table)查看。
2、pd.crosstab()交叉表功能,有同樣的效果,作用對象是Pandas
參數margins=False表示不分類匯總,True表示分類匯總
help(df.pivot_table)
pivot_table(values=None, index=None, columns=None, aggfunc='mean', fill_value=None, margins=False, dropna=True, margins_name='All') help(pd.crosstab): crosstab(index, columns, values=None, rownames=None, colnames=None, aggfunc=None, margins=False, margins_name='All', dropna=True, normalize=False)題目11:
使用透視表查看每個員工在不同柜臺上班的次數:
df.pivot_table(index="姓名",columns="柜臺",values="交易額",aggfunc="count",margins=True) --------------------------------------------------------------------- out:本文涉及數據處理,數據分析,統計展示,輸入輸出。
lambda表達式,apply()系列函數,pivot,pivot_table()函數,crosstab()函數,上下文管理器,分組聚合,數據篩選,字符處理,數據透視。文章不長,但是涉及內容精簡實用,可以做實際應用中體會。
知乎排版太難看,請參考原文
Pandas綜合案例:超市營業額數據實戰分析?mp.weixin.qq.com公眾號“python數據科學修煉之路”
總結
以上是生活随笔為你收集整理的python 数据分析 实际案例_python实战案例:超市营业额数据分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python批量访问网页保存结果_Pyt
- 下一篇: android 界面绘制完毕,几种获取a