在數(shù)據(jù)分析時(shí),用Python進(jìn)行數(shù)據(jù)處理主要使用的兩個(gè)包:Numpy、Pandas。Numpy包是數(shù)值編程工具:N維數(shù)組對(duì)象:ndarray,對(duì)數(shù)組結(jié)構(gòu)數(shù)據(jù)進(jìn)行運(yùn)算(不用遍歷循環(huán)),有隨機(jī)數(shù)、線性代數(shù)、傅里葉變換等功能。Pandas包是基于Numpy構(gòu)建,為數(shù)據(jù)分析而存在,有一維數(shù)組Series 和二維數(shù)組 Dataframe,可直接讀取數(shù)據(jù)并做處理(高效簡(jiǎn)單),兼容各種數(shù)據(jù)庫(kù)并支持各種分析算法。數(shù)據(jù)處理主要有一維的行或列,還有二維的行和列(類似EXCEL),Numpy和Pandas也有一維、二維數(shù)據(jù),并且在Numpy的基礎(chǔ)上的Pandas的一維數(shù)組Series 和二維數(shù)組 Dataframe可以更高效處理數(shù)據(jù)。主要將從一維數(shù)據(jù)開(kāi)始,然后再到二維數(shù)據(jù),再以一個(gè)數(shù)據(jù)分析的案例來(lái)學(xué)習(xí)數(shù)據(jù)分析的基本過(guò)程。 import numpy as np #導(dǎo)入numpy包
import pandas as pd #導(dǎo)入pandas包
已設(shè)置了Numpy、Pandas簡(jiǎn)稱,后續(xù)以np、pd表示
1、一維數(shù)據(jù)分析 1.1、一維數(shù)據(jù)分析:Numpy 1)、一維數(shù)組array的定義,可以使用到numpy.array()函數(shù)去設(shè)置。 #定義:一維數(shù)組array,參數(shù)傳入的是一個(gè)列表[2,3,4,5,6,8,9] ar = np.array([2,3,4,5,6,8,9]) print('輸出數(shù)組ar:',ar) #輸出數(shù)組ar print('數(shù)組ar的數(shù)據(jù)類型:',type(ar)) #數(shù)組ar的數(shù)據(jù)類型 生成結(jié)果: 2、查詢使用使用索引位置下標(biāo)。 #查詢,使用索引位置下標(biāo)
ar[1]
print('ar[1]輸出結(jié)果:',ar[1])
生成結(jié)果: 查詢的原理如下圖: 3、切片訪問(wèn):獲取指定序號(hào)范圍的元素。 #切片訪問(wèn):獲取指定序號(hào)范圍的元素 ar[1:3] #a[1:3]獲取到的是序號(hào)從1到2的元素,他是一個(gè)左閉右開(kāi)的區(qū)間 print('ar[1:3]輸出結(jié)果:',ar[1:3]) 生成結(jié)果: 切片訪問(wèn)的原理如下圖: 4、查看數(shù)據(jù)類型dtype。 #查看數(shù)據(jù)類型dtype
ar.dtype
print('查看ar的數(shù)據(jù)類型:',ar.dtype)
生成結(jié)果: 5、統(tǒng)計(jì)計(jì)算。 print('ar內(nèi)數(shù)據(jù)的平均值:',ar.mean()) #計(jì)算平均值 print('ar內(nèi)數(shù)據(jù)的標(biāo)準(zhǔn)差:',ar.std ()) #計(jì)算標(biāo)準(zhǔn)差 print('ar內(nèi)數(shù)據(jù)的方差:',ar.var()) #計(jì)算方差 print('ar內(nèi)數(shù)據(jù)的最大值:',ar.max()) #計(jì)算最大值 print('ar內(nèi)數(shù)據(jù)的最小值:',ar.min()) #計(jì)算最小值 生成結(jié)果: 6、向量化運(yùn)行:乘以標(biāo)量 ar_1 = ar*10 #ar內(nèi)每個(gè)元素都乘以10
print('輸出ar_1的結(jié)果是:',ar_1)
生成結(jié)果: 1.2、一維數(shù)據(jù)分析:Pandas 1)、定義:Pandas一維數(shù)據(jù)結(jié)構(gòu):Series。 stockS=pd.Series([54.74,190.9,173.14,1050.3,181.86,1139.49], index=['騰訊', '阿里巴巴', '蘋果', '谷歌', 'Facebook', '亞馬遜']) #創(chuàng)建Series print(stockS) 生成結(jié)果: 2)、獲取描述統(tǒng)計(jì)信息。 sm = stockS.describe()
print('輸出stockS數(shù)據(jù)的描述統(tǒng)計(jì)信息:\n',sm)
3)、iloc屬性用于根據(jù)索引獲取值。 st0 = stockS.iloc[0] #按照整數(shù)的行位置進(jìn)行索引 print('輸出stockS行號(hào)為0的數(shù)據(jù):',st0) 生成結(jié)果: 4)、loc屬性用于根據(jù)索引獲取值。 st_tx = stockS.loc['騰訊'] #按照行名進(jìn)行索引
print('輸出stockS行名“騰訊”的數(shù)據(jù):',st_tx)
生成結(jié)果: 5)、向量化運(yùn)算:向量相加(根據(jù)標(biāo)簽自動(dòng)對(duì)齊,)。 s1=pd.Series([1,2,3,4],index=['a','b','c','d']) s2=pd.Series([10,20,30,40],index=['a','b','e','f']) s3=s1 s2 #根據(jù)標(biāo)簽自動(dòng)對(duì)齊,空值和任何值計(jì)算結(jié)果扔為空值 print('輸出s3的結(jié)果:\n',s3) 生成結(jié)果: 6)、處理缺失值:NaN 方法1:刪除缺失值
s3_notna = s3.dropna()
print('將s3刪除缺失值后:\n',s3_notna)
生成結(jié)果: 方法2:將缺失值進(jìn)行填充 s3=s1.add(s2,fill_value=0) print('s1與s2進(jìn)行向量相加時(shí),出現(xiàn)缺失值直接補(bǔ)0,得到s3為:\n',s3) 生成結(jié)果: 2、二維數(shù)據(jù)分析 2.1、二維數(shù)據(jù)分析:Numpy 1)、二維數(shù)組array的定義,可以使用到numpy.array()函數(shù)去設(shè)置。 #定義二維數(shù)組
ar=np.array([[1,2,3,4],
[5,6,7,8],
[9,10,11,12]])
print('輸出數(shù)組ar:\n',ar) #輸出數(shù)組ar
生成結(jié)果: 2)、索引與切片 #獲取行號(hào)是0,列號(hào)是2的元素a[0,2] ar[0,2] #獲取第1行 ar[:,0] #獲取第1列 ar[0,:] print('輸出ar[0,2]:',ar[0,2]) print('獲取第1行:',ar[:,0]) print('獲取第1列:',ar[0,:]) 生成結(jié)果: 3)、Numpy數(shù)軸參數(shù):axis,axis=0是列方向,axis=1是行方向。 #如果沒(méi)有指定數(shù)軸參數(shù),會(huì)計(jì)算整個(gè)數(shù)組的平均值
print('ar內(nèi)所有數(shù)求平均:',ar.mean())
#按軸計(jì)算:axis=0計(jì)算每一列
print('ar內(nèi)每一列數(shù)求平均:',ar.mean(axis = 0))
#按軸計(jì)算:axis=1計(jì)算每一行
print('ar內(nèi)每一行數(shù)求平均:',ar.mean(axis = 1))
生成結(jié)果: 2.2、Pandas二維數(shù)組:數(shù)據(jù)框(DataFrame) 1)、二維數(shù)組DataFrame的定義。 #第1步:定義一個(gè)有序的元組 salesDict=( ('購(gòu)藥時(shí)間',['2018-01-01 星期五','2018-01-02 星期六','2018-01-06 星期三']), ('社??ㄌ?hào)',['001616528','001616528','0012602828']), ('商品編碼',[236701,236701,236701]), ('商品名稱',['強(qiáng)力VC銀翹片','清熱解毒口服液','感康']), ('銷售數(shù)量',[6,1,2]), ('應(yīng)收金額',[82.8,28,16.8]), ('實(shí)收金額',[69,24.64,15])) #導(dǎo)入有序字典 from collections import OrderedDict #定義一個(gè)有序字典 salesOrderDict=OrderedDict(salesDict) #定義數(shù)據(jù)框:傳入字典,列名 salesDf=pd.DataFrame(salesOrderDict) salesDf 生成結(jié)果: 2)、按每列或行來(lái)求值。 print('默認(rèn)按列進(jìn)行運(yùn)算:\n',salesDf.mean())
print('--------------')
print('axis=1時(shí)按行進(jìn)行運(yùn)算:\n',salesDf.mean(axis=1))
生成結(jié)果: 3)、 查詢數(shù)據(jù):iloc屬性用于根據(jù)位置獲取值 #查詢第1行第2列的元素 salesDf.iloc[0,1] #獲取第1行,:代表所有列 salesDf.iloc[0,:] #生成一個(gè)Series #獲取第1列,:代表所有行 salesDf.iloc[:,0] #生成一個(gè)Series print('查詢第1行第2列的元素:',salesDf.iloc[0,1]) print('---------') print('獲取第1行:\n',salesDf.iloc[0,:]) print('---------') print('獲取第1列:\n',salesDf.iloc[:,0]) 生成結(jié)果: 4)、 查詢數(shù)據(jù):loc屬性用于根據(jù)索引獲取值。 #查詢第1行第1列的元素
salesDf.loc[0,'商品編碼']
#獲取第1行
salesDf.loc[0,:]
#簡(jiǎn)單方法:獲取“商品名稱”這一列
salesDf['商品名稱']
print('第1行第1列的元素:',salesDf.loc[0,'商品編碼'])
print('--------------')
print('獲取第1行:\n',salesDf.loc[0,:])
print('--------------')
print('簡(jiǎn)單方法:獲取“商品名稱”這一列\(zhòng)n',salesDf['商品名稱'])
生成結(jié)果: #通過(guò)列表來(lái)選擇某幾列的數(shù)據(jù) salesDf[['商品名稱','銷售數(shù)量']] #通過(guò)切片功能,獲取指定范圍的列 salesDf.loc[:,'購(gòu)藥時(shí)間':'銷售數(shù)量'] print('查看商品名稱、銷售數(shù)量數(shù)據(jù):\n',salesDf[['商品名稱','銷售數(shù)量']]) print('------------') print('查看購(gòu)藥時(shí)間到銷售數(shù)量各列數(shù)據(jù):\n',salesDf.loc[:,'購(gòu)藥時(shí)間':'銷售數(shù)量']) 生成結(jié)果: 5)、條件判斷 #通過(guò)條件判斷篩選
#第1步:構(gòu)建查詢條件
querySer=salesDf.loc[:,'銷售數(shù)量']>1
#第1步:將查詢條件寫入
salesDf1 = salesDf.loc[querySer,:]
print('銷售數(shù)量大于1的數(shù)據(jù):\n',salesDf1)
生成結(jié)果: 6)、 查看數(shù)據(jù)集描述統(tǒng)計(jì)信息 #讀取Ecxcel數(shù)據(jù) import os os.chdir(r'D:\data3') fileNameStr='朝陽(yáng)醫(yī)院2018年銷售數(shù)據(jù).xlsx' xls = pd.ExcelFile(fileNameStr) salesDf = xls.parse('Sheet1') #打印出前3行,以確保數(shù)據(jù)運(yùn)行正常 salesDf.head(3) 生成結(jié)果: #有多少行,多少列
salesDf.shape
生成結(jié)果: #查看某一列的數(shù)據(jù)類型 salesDf.loc[:,'銷售數(shù)量'].dtype 生成結(jié)果: #查看每一列的統(tǒng)計(jì)數(shù)值
c = salesDf.describe()
生成結(jié)果: 3、案例:藥店銷售數(shù)據(jù)分析 數(shù)據(jù)分析的基本過(guò)程:1、 提出問(wèn)題→2、理解數(shù)據(jù)→3、數(shù)據(jù)清洗→4、構(gòu)建模型→5、數(shù)據(jù)可視化。 3.1、提出問(wèn)題 可以從銷售數(shù)據(jù)中分析出業(yè)務(wù)指標(biāo): 1)、月均消費(fèi)次數(shù); 2)、月均消費(fèi)金額; 3)、客單價(jià); 3.2、理解數(shù)據(jù) 1)、讀取銷售數(shù)據(jù) import pandas as pd fileNameStr='D:/data3/朝陽(yáng)醫(yī)院2018年銷售數(shù)據(jù).xlsx' xls = pd.ExcelFile(fileNameStr) salesDf = xls.parse('Sheet1') 2)、查看數(shù)據(jù)基本信息 #打印出前5行,以確保數(shù)據(jù)運(yùn)行正常
salesDf.head()
生成結(jié)果: #有多少行,多少列 salesDf.shape 生成結(jié)果: 即數(shù)據(jù)有6578行,7列。 #查看每一列的數(shù)據(jù)類型
salesDf.dtypes
生成結(jié)果: 3.3、數(shù)據(jù)清洗 數(shù)據(jù)清洗有6個(gè)基本步驟:1、選擇子集;2、列名重命名;3、缺失數(shù)據(jù)處理;4、數(shù)據(jù)類型轉(zhuǎn)換;5、數(shù)據(jù)排序;6、異常值處理。這次使用的數(shù)據(jù)列數(shù)字段較少,不需要選擇子集。 1)、 列名重命名 colNameDict = {'購(gòu)藥時(shí)間':'銷售時(shí)間'} #字典:舊列名和新列名對(duì)應(yīng)關(guān)系 salesDf.rename(columns = colNameDict,inplace=True) #在原表上將購(gòu)藥時(shí)間列名改為銷售時(shí)間 salesDf.head() 生成結(jié)果: 2)、 缺失數(shù)據(jù)處理 python缺失值有3種:1、Python內(nèi)置的None值;2、在pandas中,將缺失值表示為NA,表示不可用not available;3、對(duì)于數(shù)值數(shù)據(jù),pandas使用浮點(diǎn)值NaN(Not a Number)表示缺失數(shù)據(jù)。 #刪除列(銷售時(shí)間,社??ㄌ?hào))中為空的行
salesDf=salesDf.dropna(subset=['銷售時(shí)間','社保卡號(hào)'],how='any')#how='any' 在給定的任何一列中有缺失值就刪除
print('刪除缺失后大小',salesDf.shape)
生成結(jié)果: 3)、數(shù)據(jù)類型轉(zhuǎn)換 從數(shù)據(jù)上看,銷售時(shí)間是一個(gè)文本形式的數(shù)據(jù),需要將數(shù)據(jù)轉(zhuǎn)換為日期數(shù)據(jù)類型。銷售時(shí)間一列的數(shù)據(jù) 是以空格分開(kāi)一個(gè)標(biāo)準(zhǔn)日期和一個(gè)星期幾的格式,需要編寫一個(gè)函數(shù),分割銷售日期的前一分部,獲取銷售日期。 def splitSaletime(timeColSer): timeList=[] #自建一個(gè)空列表,將處理完的數(shù)據(jù)存入 for value in timeColSer: dateStr=value.split(' ')[0] #例如2018-01-01 星期五,分割后為:2018-01-01 timeList.append(dateStr) #將分割后的日期格式存入空列表 timeSer=pd.Series(timeList) #將列表轉(zhuǎn)行為一維數(shù)據(jù)Series類型 return timeSer 使用定義好的splitSaletime函數(shù)處理“銷售時(shí)間”這一列的數(shù)據(jù)。 timeSer=salesDf.loc[:,'銷售時(shí)間'] #獲取“銷售時(shí)間”這一列
dateSer=splitSaletime(timeSer) #對(duì)字符串進(jìn)行分割,獲取銷售日期
dateSer.head() #查看處理的結(jié)果
生成結(jié)果: 將“銷售時(shí)間”這一列的數(shù)據(jù)修改為處理好的“dateSer”數(shù)據(jù)。 salesDf.loc[:,'銷售時(shí)間']=dateSer #修改銷售時(shí)間這一列的值 salesDf.head() #查看處理的結(jié)果 生成結(jié)果: 因?yàn)椤颁N售時(shí)間”這一列數(shù)據(jù)類型還是屬于字符類型,需要轉(zhuǎn)化為時(shí)間類型。 salesDf.loc[:,'銷售時(shí)間']=pd.to_datetime(salesDf.loc[:,'銷售時(shí)間'],
format='%Y-%m-%d',
errors='coerce')
#errors='coerce' 如果原始數(shù)據(jù)不符合日期的格式,轉(zhuǎn)換后的值為空值NaT
#format 是你原始數(shù)據(jù)中日期的格式
salesDf.dtypes #查看處理后的數(shù)據(jù)類型
生成結(jié)果: 因?yàn)樵凇颁N售時(shí)間”轉(zhuǎn)化為時(shí)間類型時(shí),會(huì)有空值產(chǎn)生。還有“社保卡號(hào)”這一列也不能這空值,所以要將“銷售時(shí)間”、“社??ㄌ?hào)”這一列出現(xiàn)空值的行刪除。 salesDf=salesDf.dropna(subset=['銷售時(shí)間','社??ㄌ?hào)'],how='any') #刪除列(銷售時(shí)間,社??ㄌ?hào))中為空的行 salesDf.shape #查看處理后的數(shù)據(jù)行數(shù)與列數(shù) 生成結(jié)果: 4)、 數(shù)據(jù)排序 從數(shù)據(jù)上看,以時(shí)間為維度可以對(duì)“銷售時(shí)間”排序,并且排序后由于行名會(huì)有變化,所以重名行名(index). salesDf=salesDf.sort_values(by='銷售時(shí)間',ascending=True,na_position='first')
#by:按哪幾列排序
#ascending=True 表示升序排列
#ascending=False表示降序排列
#na_position=True表示排序的時(shí)候,把空值放到前列
salesDf=salesDf.reset_index(drop=True)
print('排序后并修改行名的數(shù)據(jù)集')
salesDf.head() #查看數(shù)據(jù)排序后的結(jié)果
生成結(jié)果: 5)、異常值處理 從數(shù)據(jù)上看,銷售數(shù)量是關(guān)聯(lián)到應(yīng)收金額、實(shí)收金額,首先銷售數(shù)量不能小于0,先簡(jiǎn)單查看數(shù)據(jù)的統(tǒng)計(jì)情況。 salesDf.describe() #查看每列的統(tǒng)計(jì)值 生成結(jié)果: 刪除異常值:通過(guò)條件判斷篩選出數(shù)據(jù)。 querySer=salesDf.loc[:,'銷售數(shù)量']>0 #查詢條件,生成一個(gè)大于0的布爾值數(shù)據(jù)列
print('刪除異常值前:',salesDf.shape)
salesDf=salesDf.loc[querySer,:] #應(yīng)用查詢條件
print('刪除異常值后:',salesDf.shape)
salesDf.describe() #查看每列的統(tǒng)計(jì)值
生成結(jié)果: 3.4、構(gòu)建模型 1)、 月均消費(fèi)次數(shù)=總消費(fèi)次數(shù) / 月份數(shù); 其中對(duì)于消費(fèi)次數(shù)的定義再細(xì)化:同一天內(nèi),同一個(gè)人發(fā)生的所有消費(fèi)應(yīng)該是算做一次消費(fèi)。從數(shù)據(jù)的計(jì)算實(shí)現(xiàn)來(lái)操作,可以根據(jù)”銷售時(shí)間“和”社區(qū)卡號(hào)“,兩列值只取唯一值,也就是如果兩值同時(shí)相同,就只保留1條,將重復(fù)的刪除。 kpi1_Df=salesDf.drop_duplicates(subset=['銷售時(shí)間', '社??ㄌ?hào)']) totalI=kpi1_Df.shape[0] #獲取行數(shù),即是總消費(fèi)次數(shù) print('總消費(fèi)次數(shù)=',totalI) 生成結(jié)果: 月份數(shù)的計(jì)算,通過(guò)對(duì)銷售時(shí)間排序,得到最小時(shí)間與最大時(shí)間,再用最大時(shí)間減最小時(shí)間并整除30(簡(jiǎn)化計(jì)算),最終得到月份數(shù)。 #第1步:按銷售時(shí)間升序排序
kpi1_Df=kpi1_Df.sort_values(by='銷售時(shí)間',
ascending=True)
#重命名行名(index)
kpi1_Df=kpi1_Df.reset_index(drop=True)
kpi1_Df.head()
kpi1_Df.tail() #相看結(jié)果
生成結(jié)果: #第2步:獲取時(shí)間范圍 startTime=kpi1_Df.loc[0,'銷售時(shí)間'] #最小時(shí)間值 endTime=kpi1_Df.loc[totalI-1,'銷售時(shí)間'] #最大時(shí)間值 #第3步:計(jì)算月份數(shù) daysI=(endTime-startTime).days #天數(shù) monthsI=daysI//30 #月份數(shù) print('月份數(shù):',monthsI) 生成結(jié)果: #業(yè)務(wù)指標(biāo)1:月均消費(fèi)次數(shù)=總消費(fèi)次數(shù) / 月份數(shù)
kpi1_I=totalI // monthsI
print('業(yè)務(wù)指標(biāo)1:月均消費(fèi)次數(shù)=',kpi1_I)
生成結(jié)果: 2)、月均消費(fèi)金額 = 總消費(fèi)金額 / 月份數(shù); 其中月份數(shù)計(jì)算出來(lái),現(xiàn)在要計(jì)算的是總消費(fèi)金額,只要對(duì)”實(shí)收金額“這一列相加就可以獲得總消費(fèi)金額。 totalMoneyF=salesDf.loc[:,'實(shí)收金額'].sum() #總消費(fèi)金額 monthMoneyF=totalMoneyF / monthsI #月均消費(fèi)金額 print('業(yè)務(wù)指標(biāo)2:月均消費(fèi)金額=%.2f'%(monthMoneyF)) 生成結(jié)果: 3)、 客單價(jià)=總消費(fèi)金額 / 總消費(fèi)次數(shù) 其中總消費(fèi)金額和總消費(fèi)次數(shù)在前面的計(jì)算過(guò)程已有,直接調(diào)用就可以。即totalMoneyF是總消費(fèi)金額,totalI是總消費(fèi)次數(shù)。 pct=totalMoneyF / totalI #月均消費(fèi)金額
print('客單價(jià):%.2f'%pct)
生成結(jié)果: 由此得到幾點(diǎn): 1、數(shù)據(jù)分析有一個(gè)基本的套路:1)、提出問(wèn)題;2)、理解數(shù)據(jù);3)、數(shù)據(jù)清洗;4)、構(gòu)建模型;5)、數(shù)據(jù)可視化(待續(xù))。 2、數(shù)據(jù)清潔的基本過(guò)程:1)、選擇子集;2)、列名重命名;3)、缺失數(shù)據(jù)處理;4)、數(shù)據(jù)類型轉(zhuǎn)換;5)、數(shù)據(jù)排序;6)、異常值處理。 |
|