近期做了四個Python數(shù)據(jù)分析的案例實踐柬采,把流程捞稿、語句和想法歸納總結罩息,做一個小小的里程碑
1.流程
明確分析目的->由數(shù)據(jù)源構建指標體系->數(shù)據(jù)清洗->數(shù)據(jù)處理及分析->結論
2.明確分析目的
-->分析問題產(chǎn)生的原因/分析業(yè)務現(xiàn)狀/通過分析對業(yè)務進行指導……
目的——是具體的、充滿定語的茫经、具有返回值的
3.由數(shù)據(jù)源構建指標體系
區(qū)分維度和指標:
維度:對應數(shù)據(jù)的每一列巷波,多個列組合也可以認為是一個維度
指標:各種統(tǒng)計值
在不同維度上得到各種指標
根據(jù)不同數(shù)據(jù)源和分析目的搭建指標體系
eg:一款付費軟件的日活/人均付費/付費渠道/付費功能/使用頻次/使用時長……
4.數(shù)據(jù)清洗
4.1導入庫
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
4.2加載文件
df = pd.read_csv('./file.csv')
4.3簡單查看數(shù)據(jù)有哪些列&類型
df.info() # 可看到缺失行在某一列上的條目數(shù)少于總數(shù),但當列數(shù)目較多時卸伞,不容易發(fā)現(xiàn)
df.head()
4.4查看數(shù)據(jù)的整體信息
df.describe() # 整數(shù)型或浮點型數(shù)據(jù)
df.count() # 查看各列非空數(shù)據(jù)量
4.5開始數(shù)據(jù)清理
->對需要分析的維度進行清理
->對于數(shù)值型數(shù)據(jù)抹镊,可以通過describe方法輸出信息,關注最大值瞪慧、最小值髓考、平均值、行數(shù)等是否符合常理或是否滿足本次數(shù)據(jù)分析目的對數(shù)據(jù)的要求
4.5.1判斷數(shù)據(jù)是否有null值弃酌、0值等
若null值所在行數(shù)較少,刪除后不會對總體數(shù)據(jù)產(chǎn)生較大影響
df[df.salary.isnull()] 輸出salary列null值所在行的全部信息
df.drop(df[df.salary.isnull()].index, inplace = True)
df[df.salary.isnull()] # 查看是否刪除成功
若不想刪除數(shù)據(jù)儡炼,則可用聚合函數(shù)或前值/后值等替換處理妓湘,如使用平均數(shù)替換
df['salary'].replace(0,df['salary'].mean(), inplace = True)
# 注:若遇到較多0值,且要采用平均數(shù)填充乌询,可先將0值替換為np.nan榜贴,再使用列名.fillna()填充該列數(shù)據(jù)平均數(shù),這樣在計算平均數(shù)時nan所在行不會對整體平均數(shù)產(chǎn)生影響(不計入在內)
df.salary.replace(0,np.nan, inplace = True)
df.salary.fillna(df['salary'].mean(), inplace=Ture)
df['communityAverage'].fillna(df['communityAverage'].mean(), inplace=True) # 對null值妹田,也可使用fillna
df.info() 查看是否有Nan值
Nan非null值唬党,無法用 .isnull()判斷
但通過df.info()判斷存在缺失值,但又不是null時鬼佣,可查看其是否為Nan值
df['Type'].value_counts(dropna = False) #統(tǒng)計包括Nan在內的數(shù)據(jù)
data.dropna() # 默認axis=0,how='any',刪除帶有空值的行驶拱,只要有一個空值,就刪除整行
df.dropna(how='all') # 整行都是空值時晶衷,才會被刪除
df.dropna(how='all',axis=1)) # 整列都是空值時蓝纲,才會被刪除
df.dropna(subset=[1,2]) # 刪除指定1和2列中包含缺失值的行
4.5.2 查看是否具有重復值阴孟,展示重復的條目
如果有重復值,?般最后處理税迷,因為其他的列可能會影響到刪除那?條重復的記錄
先處理其他的列
df[df.duplicated()] #注意這樣使用是展示各字段完全相同的條目
df.drop_duplicates('App', inplace = True)# 刪除'App'列中數(shù)據(jù)重復的行
也可根據(jù)指定部分列(待分析列)是否具有重復值
df[df[:,['employee_ID','deptno_ID','salary']].dupliacted()]
df[df.employee_ID.dupliacted()] # 單獨查看employee_ID是否具有重復值的條目
或使用行數(shù)是否相等來判斷
len(df.empolyee_ID.unique()) 與 len(df) # 是否相等永丝,相等->該列無重復
df['employee_ID'].value_counts() # 默認剔除nan值 # 是否有大于1的
df['employee_ID'].value_counts(dropna = False) # 計算包含nan值的條目
pd.unique(df['employee_ID']).size # 是否與整個數(shù)據(jù)行數(shù)相同
注意:當我們對?列取size屬性的時候,返回的是?數(shù)箭养,如果對于dataframe使?size慕嚷,返回的是行乘以列的結果,也就是總的元素數(shù)
4.5.3 刪除非所需數(shù)據(jù)
df.drop(df[df['hiretime'].dt.year<2015].index, inplace = True)
df.drop(df[df['hiretime'].dt.year>2019].index, inplace = True)
df['hiretime'].dt.year.value_counts()
4.5.4 使用分類查看是否有不合邏輯的類型
df['nationality'].value_counts()
比如該列都是用國家英文全稱來填充的毕泌,但某個結果中若出現(xiàn)數(shù)字-->不合邏輯-->是因為沒有把數(shù)字標號轉換為國家還是因為其他原因闯冷?
4.5.5 判斷字符串類型數(shù)據(jù)是否只由數(shù)字組成
df['deptno_info'].str.isnumeric() --> True or False
df['deptno_info'].str.isnumeric().sum() -->True 的條目數(shù)
數(shù)據(jù)格式轉換
df['deptno_info'].astype('i8') #將本列轉換為數(shù)值格式
說明:
isnumeric() 方法檢測字符串是否只由數(shù)字組成。這種方法是只針對unicode對象懈词。
注:定義一個字符串為Unicode蛇耀,只需要在字符串前添加 'u' 前綴即可,如 str1 = u'Itachi';
對于 Unicode 數(shù)字坎弯、全角數(shù)字(雙字節(jié))纺涤、羅馬數(shù)字和漢字數(shù)字會返回 True ,其他會返回 False抠忘。byte數(shù)字(單字節(jié))無此方法撩炊。
print u'123'.isnumeric() # True
print u'Ⅷ'.isnumeric() # True
print u'abc123'.isnumeric() # False
print u'1.23'.isnumeric() # False
4.5.6 單位轉化 str.replace()
eg:數(shù)據(jù)單位的簡化處理
tips:轉化為數(shù)據(jù)較小單位時可以實現(xiàn)-->轉化后數(shù)據(jù)成為整數(shù)int類型,而非float
df['size'] = df['size'].replace('M','e+6') #M-->10^6
df['size'] = df['size'].replace('k','e+3') #k-->10^3
df['size'] = df['size'].replace(',','') # 替換千位符
df['Size'].astype('f8')
使用is_convertable(v)函數(shù)定義一個方法崎脉,判斷字符串判斷是否可以轉換
def is_convertable(v):
try:
float(v)
return True
except ValueError:
return False
查看不能轉換的字符串分布
temp = df['size'].apply(is_convertable) -->能轉換 True
df['size'][-temp].value_counts() --> -temp 取False的
# 轉換剩下的字符串
df['size'] = df['size'].str.replace('Varies with device','0')
# 再看下是不是還有沒轉換的字符串
temp = df['size'].apply(is_convertable)
df['size'][-temp].value_counts()
# 轉換類型
# e+5這種格式使?astype直接轉為int有問題拧咳,如果想轉成int,可以先轉成f8囚灼,再轉i8
#df['size'] = df['size'].astype('f8').astype('i8')
df['size'] = df['size'].astype('i8')
# 將size為0的填充為平均數(shù)
df['size'].replace(0,df['size'].mean(), inplace = True)
df.describe()
5.數(shù)據(jù)分析
5.1樣本總數(shù)
df.count()
5.2數(shù)值類型列的常見統(tǒng)計指標
df.describe()
5.3采用不同維度和指標進行分析
① 分組 groupby
分組統(tǒng)計不同國家人員并保留兩列
nationality_data = df.groupby('nationality',as_index = False).count()[['nationality', 'ID']]
nationality_data.rename(columns={'ID':'employee_count'},inplace = True) #重命名ID列-->上述操作后ID列實際為總數(shù)
不同部門中雇員平均工資
deptno_data = df.groupby('deptno',as_index = False).mean()[['deptno','salary']
對不同分組下另一維度進行排序
eg:對App分類分組后計算其他維度平均值骆膝,并按照平均安裝量對各組降序排列
df.groupby('category').mean().sort_values('installs', ascending = False)
多列分組
# type --> free or charges
# category --> family or media or chat ..........
df.groupby(['type','category'].mean().sort_values('reviews', ascending = True/False, inplace = True/False)
② 分類計數(shù)
groupby().count()
df.groupby('nationality').count()
value_counts()
eg:統(tǒng)計每年入職人數(shù)
年份跨度較大時灶体,有些年份可能數(shù)據(jù)較少阅签;年初或年中時,當年數(shù)據(jù)可能較少
看下每年數(shù)據(jù)的數(shù)量蝎抽,確定是否要刪除數(shù)據(jù)少的年份
將字符串轉化為日期格式政钟,方便使用內置函數(shù)
df['hiretime'] = pd.to_datetime(df['hiretime'])
df['hiretime'].dt.year.value_counts()
分類計算比例
eg:對類型和分類分組后,對其評論安裝比進行排序
g = df.groupby(['type','category']).mean()
(g['reviews'] / g['installs']).sort_values(ascending = False)
③ 按照數(shù)值排序 sort_values()
nationality_sorted_data = nationality_data.sort_values('employee_count', ascending=False)
nationality_sorted_data[nationality_sorted_data.employee_count>100] # 顯示employee_count數(shù)量大于100的數(shù)據(jù)列表
df.sort_index(inplace = True) # 按照索引排序 sort_index()
④ 分桶 pd.cut-groupby
雇員年齡分布
生成桶樟结,5歲一個分桶 最小18歲养交,最大60歲
bins = np.arange(18,63,5)
bins_data = pd.cut(df['age'],bins)
bin_counts = df['age'].groupby(bins_data).count()
# 為圖表展示好看使用列表生成式處理index
bin_counts.index = [str(x.left) + '-' + str(x.right) for x in bin_counts.index]
⑤ 單獨取出某列
eg:取出2017年,國籍為China的所有數(shù)據(jù)
df_2017 = df[df['hiretime'].dt.year == 2017]
df_2017_China = df_2017[df_2017['nationality'] == 'China']
df_2017_China.describe()
⑥ 占比 len()/len()
統(tǒng)計salary在50~100之間的數(shù)據(jù)在所有數(shù)據(jù)中的占比
len(df[df['salary'] > 50]) & len(df[df['salary'] < 100])/len(df)
⑦ 相關性(0.5以上可以認為相關瓢宦,0.3以上可以認為是弱相關)
df.corr() # 列出二維相關性表
⑧ .head() .tail()
# 取某維度的前十名和后十名
print(product_orderby_count.head(10))
print(product_orderby_count.tail(10))
⑨ .intersection() 交集
看下銷售額和銷量最后100個的交集碎连,如果銷售額和銷量都不行,這些商品需要看看是不是要優(yōu)化或者下架
problem_productids = productid_turnover.tail(100).intersection(product_orderby_count.tail(100).index)
5.4 matplotlib查看數(shù)據(jù)效果
bin_counts.plot()
plt.show()
注意點:
1.drop刁笙、rename等方法具有inplace參數(shù)破花,具體見幫助文檔谦趣,學習初期往往忽略此參數(shù),導致數(shù)據(jù)未在原表上修改或未設置接收變量座每。運行后無輸出則說明inplace為TRUE(jupyter notebook的使用優(yōu)點)前鹅,若有輸出則應賦予接收變量或為inplace賦值;而replace沒有inplace參數(shù)峭梳,需要設置接收值
2.對多列進行操作時舰绘,留心是否需要多加一層括號,如 df.groupby(['district', 'elevator'])
3.注意到df_dis_want[(df['year'] == '2017')]判別條件這里葱椭,數(shù)據(jù)類型不同判別條件中需要考慮是否加引號''捂寿,或者可認為是數(shù)據(jù)清洗環(huán)節(jié)的疏漏