儒冠多誤身
2019.04.20個人總結
- 第一步:備份源數據到其他盤符、硬盤、u盤、網盤等
- 需求分析
- 數據提取
- 數據清洗
- 數據分析
- 報告撰寫
- 報告分享
- 投入應用收集反饋
文章目錄
1. 目標確定
2. 數據獲取
數據來源
- 數據可信度
3. 數據清洗
3.1 預處理
3.1.1 讀取
pd.read_csv('demo.csv',na_values=['XYZ','NA','-999',0])
3.1.2 觀察
-
基本框架
.shape .info() .head() pd.value_counts(df['col']) df['col'].value_counts()
-
數據特徵
- 連續型數據
- 離散型數據
-
索引值是可以重複的
df.index.is_unique
-
重命名
df.rename(index=str.lower,columns={'col1':'a','col2':'b'})
3.1.3 關聯
-
pd.merge(),相當於SQL的join
pd.merge(left,right,left_on=,right_on=,suffixes=('_x','__y'))
-
pd.concat(),堆疊
pd.concat([df1,df2,df3,s1],axis=1)# index pd.concat([s1,s2,s3])
- axis=0,columns
-
df1.join(df2)
,按照index連接 -
df1.combine_first(df2)
,修補- 結果會同時包含df1和df2的行與列
- df1的缺失值NaN,會被df2對應位置的數值修補
def func(x): a = str(x) return pd.Series(a+'_a') df_new=df['col'].apply(func) df_new.rename(columns={}) df.combine_first(df_new)
-
s1.combine_first(s2)
修補 -
np.concatenate([arr1,arr2])
- axis=1,左右連接
- axis-0,堆疊
-
map函數
-
a = {'col1_1':'a','col1_3':'c'} df['col1'].map(a)
-
3.2 缺失值
3.2.1 缺失值統計
-
是否有缺失值
- 缺失的原因
-
診斷
len(df['col'].unique()) len(df) df['col'].duplicatd() df['col'].drop_duplicates() df.drop_duplicates(subset=['col1','col3'],keep=False,inpalce=True) df.isnull().values.any() df.isnull().any() df['col'].isnull() df['col'].isnull().values.any()
-
統計
df.isnull().sum() df.isnull().sum().sum() df.isnull().sum() / df.count()# 缺失值佔比
3.2.2 缺失值填充
-
捨棄
df.dropna() df.dropna(how='any') df.dropna(thresh = 3)# 每行缺失值超過3個的都捨棄 df.dropna(how='all',axis=1)# 列
-
填充
df.fillna(0) df.fillna({'col1':1,'col3':11}) df.fillna(method='ffill') df.fillna(method='bfill',limit=3)# 限制填充數量 df['col'].fillna(df['col'].mean()) df['col'].fillna(df.groupby('col')[].transform('mean'))#其結構與df的結構一致
-
內插法補齊[處理有規律數據,時間戳等]
df.interpolate()
3.3 重複值
-
統計
df.duplicated(subset=['col1','col3']).value_counts()
-
先排序,再去重
df.sort_values(by='col1').dropduplicates(subset=['col2','col3'])
- 排序會將col1列NaN值放在最下面,可確保去重時不會將該列爲NaN的值保留
- 因爲去重時,默認保留第一次出現的行
-
去重的用法
DataFrame.drop_duplicates(subset=None, keep='first', inplace=False)
- keep,默認:刪除重複項並保留第一次出現的元素
'first','last','False'
,False:一行都不保留
- keep,默認:刪除重複項並保留第一次出現的元素
3.4 轉換
3.4.1 格式轉換
-
要注意判斷,是否包含不能轉換的元素
df.col.astype()
3.4.2 字符串轉換
3.4.2.1 拆分字符串
-
拆分字符串
Series.str.split(pat=None, n=-1, expand=False)
- pat:分隔符,默認爲所有空字符,包括空格、換行符\n、製表符\t
- n:切幾刀,默認-1,有多少切多少
- expand=
- False,返回Series
- True,返回DataFrame
- 結合df1.combine_first(df_new)
- 注意column的名稱
-
統計長度不爲N的元素的個數
df1 = df['col'].str.split('_').map(len) # 判斷切割後的元素長度N (df1 != N).sum()
3.4.2.2 診斷是否包含
-
df['col'].str.contains('子字符') (~df.col1.str.contains('元/平米')).sum()
3.4.2.3 替換
-
較慢的法子
df['col'].map( lambda x:round(float(x.replace('子字符',''))/1000,2))
- round(a,2)函數,保留a,2位小數
-
推薦
round(df['col'].str.replace('子字符','').dropna().astype(np.float32).map(lambda x:x/1000),2)
3.4.2.4 類別字符串轉換爲離散變量
-
分類字符串,轉換爲離散變量
from sklearn.preprocessing import LabelEncoder le = LabelEncoder() le.fit(df['col5']) # 遍歷一遍 le.transform(df['col5']) # 將分類字符串轉換爲離散變量
apply
df['col'].apply(str.upper)
df['col'].apply(自定義函數)
def func(x):
a = x.strip().split(',')
return np.Series(a[1],a[3])
df['col'].apply(func)
3.5 邏輯錯誤值清洗
3.6 選取行列
3.6.1 sample()
-
DataFrame.sample(n=None, frac=None, replace=False,weights=None, random_state=None, axis=None*) s.sample(n=3)# 選3個隨機元素 df.sample(frac = 0.1) # 隨機取10%的元素 df.sample(n=3) # 隨機取3行
3.6.2 時間採樣
-
降採樣
s.resample('M').mean()
-
升採樣,填充
s.resample('H').ffill() s.resample('H').bfill()
-
s1.resample(freq=, # 採樣頻率字符串 axis=, # 採樣的軸,默認axis=0 fill_method=,#升採樣插值 closed=, # 降採樣中,各時間段的哪一端是閉合的,right(默認) label=, # 降採樣中,如何設置聚合值的標籤 loffset=, # 面元標籤的時間校正值 limit=, # 填充最大量 kind= # 聚合到時期或時間戳 )
3.6.3
- 結合業務,先刪除和分析無關的指標
- 查看相關係數矩陣
- 判斷各個變量相關性
- 相關性太大的可以考慮刪除此列
- 如果變量比較重要,可以考慮主成分/因子分析進行降維處理
3.7 關聯性驗證
4. 數據整理
4.1 數據規範化
4.1.1 離散化
4.1.2 歸一化
- Z-score標準化:
- 在分類、聚類算法中,需要使用距離來度量相似性的時刻,Z-score表現更好
- 經過處理的數據符合標準正太分佈,即均值0,標準差1
- 數學意義:
- 一個給定分數 距離平均數 多少個標準差
4.1.2.1 0~1標準化
-
def f(df,*cols): df_n = df.copy() for col in cols: ma = df_n[col].max() mi = df_n[col].min() df_n[col+'_n'] = (df_n[col] - mi)/(ma - mi) return(df_n) df_nc = f(df,'col1','col2')
4.1.2.2 Z標準化
-
z = (x- u) / std
-
def f_z(df,*cols): df_n = df.copy() for col in cols: u = df_n[col].mean() std = df_n[col].std() df_n[col+'_zn'] = (df_n[col]-u)/std return(df_n) df_zn = f_z(df,'col1','col2')
4.1.2.3 權重疊加
-
八類產品兩個指標val1,val2,權重分別爲0.6,0.4
- 權重統計 =(a *3 + b*2 + c *1)/6
- 先對其0~1標準化,再指標權重疊加
df_nv = f(df,'val1','val2') df_nv['f'] = df_n['val1_n']*0.6 + df_n['val2_n']*0.4 df_nv.sort_values('f',inplace=True,ascending=False) df_nv['f'].plot(style='--.k',alpha=0.8,grid=True)
4.2 指標計算
4.2.1 統計計算
4.3 格式轉換
- 轉換爲製圖、指標所需格式
5. 數據分析
5.1 單屬性(變量)分析
5.1.1 異常值分析
5.1.1.1 缺失值
df['col'].isnull().sum()
df['col'].dropna()
df['col'].fillna()
5.1.1.2 集中趨勢、離散趨勢
-
趨勢
df['col'].mean() # 均值 df['col'].median() # 中位數 df['col'].quantile(0.25) # 分位數 df['col'].std() # 標準差 df['col'].kurt() # 峯度 df['col'].skew() # 偏度 df['col'].describe() df['col'].mode() # 衆數
5.1.1.3 離羣值
-
箱線圖
- 上邊緣:Q1 - 1.5IQR
- 箱體:Q1(第一分位數),Q3(第三分位數)
- 中橫線:中位數
- 四分位差IQR: Q3-Q1
- 下邊緣:Q3 + 1.5IQR
Q3 = df['col'].quantile(0.75) Q1 = df['col'].quantile(0.25) a = Q3 - Q1 # k 取 1.5~3 df['col'][(df['col']>Q1-k*a)&(df['col']<Q3+k*a)]
切比雪夫定理
- 前提(無),經驗公式:
- 至少有75%的數據,位於平均數2個標準差範圍內
- 至少有89%的數據,位於平均數3個標準差範圍內
- 至少有96%的數據,位於平均數5個標準差範圍內
- 切比雪夫定理v2.0
- 在正態分佈中
- 正態分佈中,至少有68%的數據,位於平均數1個標準差範圍內
- 正態分佈中,至少有95%的數據,位於平均數2個標準差範圍內
- 正態分佈中,至少有99.8%的數據,位於平均數3個標準差範圍內
5.1.2結構分析
5.1.2.1 靜態結構分析
-
方法一:
sns.distplot(df['col'],kde=False)# 查看其分佈
-
方法二:
df['col'].value_counts() df['col'].value_counts(normalize=True) # 顯示爲比例 df['col'].value_counts(bins=np.arange(df['col'].min(),df['col'].max()+10,10)) # bins爲左閉右開 np.histogram(df['col'].values,bins=np.arange()) # bins爲左開右閉
-
方法三:可視化
sns.boxplot() # 箱線圖 sns.pointplot() # 折線圖 sns.countplot() # 柱狀圖 sns.displot() # 直方圖、密度圖 plt.pie() # 餅圖
5.2 雙變量
5.2.1 兩個變量間的分佈關係
5.2.1.1 散點圖
-
散點圖
sns.jointplot(x='col1', y,=col2' , data=df, kind='scatter', stat_func=<function pearsonr at 0x089DA6A8>, color=None, size=6, ratio=5, space=0.2, dropna=True, xlim=None, ylim=None, joint_kws=None, marginal_kws=None, annot_kws=None)
-
類別值間的散點圖
# 方法一 sns.stripplot(x='col1', # 類別值 y='col2', # 類別值 data=df, jitter=True # 讓繪圖點有浮動效果 ) # 方法二 sns.swarmplot(x='col1', y='col2', data=df, hue='col3' ) sns.swarmplot(x='Survived',y='Age',data=df,hue='Sex')
5.2.1.2 相關性
-
sns.regplot(x='col1', y='col2', data=df, fit_reg=False,# 不添加預測線,擬合直線 y_jitter=0.5 # 類別值,添加數據浮動 )
-
df.corr()
5.3 分佈分析
- 定性字段分佈:柱狀圖 + 餅圖
- 定量字段分佈:直方圖
5.3.1 極值差
# apply法
df[['col1','col2']].apply(lambda x:x.max() - x.min())
# 自定義函數法
def d_range(data,*cols):
krange=[]
for col in cols:
crange=df[col].max() - df[col].min()
krange.append(crange)
return(krange)
kcol1='col1'
kcol2='col2'
dr = d_range(df,kcol1,kcol2)
print('%s極差爲:%f\n%s極差爲:%f'%(kcol1,dr[0],kcol2,dr[1]))
5.3.2 頻率分佈
-
連續數據離散化
gcut = pd.cut(df['col1'],bins=10,right=False) gcut_count = gcut.value_counts(sort=False) df["%s分組區間"%kcol1]=gcut
5.3.2.1 累計頻率-帕累託分析指標
-
帕累託分析
-
先由大到小排序
-
p = df.cumsum() / df.sum() key = p[p>0.8].index[0] key_num = df.index.tolist().index(key) p.plot(style='--ko',secondary_y=True) plt.axvline(key_num,color='r',linestyle='--') plt.text(key_num+0.2,p[key],'累計佔比爲%.3f%%'%(p[key]*100),color='r')#累計佔比超過80%的節點
-
-
a = pd.DataFrame(gcut_count).rename({gcut_count.name:'頻數'},inplace=True) # 創建分組DataFrame a['頻率']=a['頻數'] / a['頻數'].sum() # 頻率 a['累計頻率']=a['頻率'].cumsum() # 累計頻率 # 轉換百分數 a['頻率']=a['頻率'].apply(lambda x:"%.2f%%"%(x*100)) a['累計頻率']=a['累計頻率'].apply(lambda x:"%.2f%%"%(x*100))
5.3.2.2 可視化
-
定量字段分佈
- 柱狀圖
- 堆積柱狀圖
- 百分比柱狀圖
plt.rcParams['font.sans-serif']=['SimHei'] # 全局設置爲黑體 plt.rcParams['axes.unicode_minus'] = False # 顯示負座標 plt.rcParams['font.size']=20 # 字號 a['頻率'].plot.bar(figsize=(12,3),alpha=0.7,grid=True) # 添加標籤 x=len(a) y=a['頻率'] m=a['頻數'] for i,j,k in zip(range(x),y,m): plt.text(i-0.1,j+0.01,'%i'%k,color='k') # 百分比柱狀圖 df.div(df.sum(1).astype(float),axis=0).plot.barh(stacked=True,color=['b','r','k','g'],fontsize=15,figsize=(12,6))
-
定性字段分佈
# 柱狀圖 cxx['頻率'].plot.bar(figsize=(12,3)) # 添加標籤 x=len(cxx) y=cxx['頻率'] m=cxx['頻數'] for i,j,k in zip(range(x),y,m): plt.text(i-0.1,j+0.01,'%i'%k,color='k') # 餅圖 plt.figure(num=2) # 餅圖在直方圖下方顯示 plt.pie(cxx['頻數'], labels=cxx.index, autopct='%.2f%%',shadow=True) plt.axis('equal')
5.1.3 對比
5.4 對比分析
- 對比分析:兩個互相聯繫的指標進行比較
5.4.1 絕對值比較(相減)
-
# 折線圖 df.plot(kind='line', style='--', alpha=0.8, figsize=(10,3) title=('AB產品銷量對比——折線圖') ) # 柱狀圖 df.plot(kind='bar', width=0.8, alpha=.8, figsize=(10,3), title='AB產品銷量對比-柱狀圖') # 相減 x=range(len(df)) y1=df['A'] y2=-df['B'] fig3 = plt.figure(figsize=(10,6)) plt.subplots_adjust(hspace=0.3) ax1=fig3.add_subplot(2,1,1) plt.bar(x,y1,width=1,facecolor='r') plt.bar(x,y2,width=1,facecolor='g') ax2 = fig3.add_subplot(2,1,2) y3 = df['A']-df['B'] plt.plot(x,y3,'--go') plt.grid() # 添加網格 plt.axhline(0,color='r',linstyle='--')# 輔助線
5.4.2 相對值比較(相除)
5.4.3 結構分析
5.4.4 比較分析
5.4.5 空間比較分析
5.4.6 動態比較分析
5.1.4 預測
5.1.5 洞察結論,製圖-看圖說話
- 根據描述分析結論,形成洞察結果
5.2 數據建模
- 模型選擇
- 模型測試
- 迭代優化
- 模型加載
5.2.1 線性迴歸(初學者)
5.2.2 聚類模型(初學者)
5.2.3
6. 可視化
1 分析圖表
單維度
- 柱狀圖
- 折線圖
- 餅圖
- 散點圖
多維度
- 熱力圖
- 箱線圖
- 矩陣
- 散點圖
空間圖表
關係圖表
2 動態交互
- Echarts
- 百度圖說
- Python與Echarts的結合
3 商業智能
- BDP
- Tableau
- power BI
- 脈策數據-Datamap
7. 業務理解
8 驗證型分析
- 基本概念
- 隨機變量
- 離散隨機變量:取值可能性有限
- 連續隨機變量:有無限個可能取值的隨機變量
- 概率分佈
- 連續隨機變量概率分佈
- 概率密度函數
- 連續隨機變量概率分佈
- 假設檢驗
- P-value
- 5%
- 1%
- 0.1%
- 中心極限定理
- 大量相互獨立的隨機變量,其均值的分佈以正態分佈爲極限
- 隨機變量
8.1 假設檢驗基本流程
- 提出零假設(我們希望推翻的結論),及備擇假設(我們希望證明的結論)
- 在零假設的前提下,推斷當前樣本統計量出現的概率
- 統計量可符合不同分佈,及對應不同的檢驗方法
- 設定一個拒絕零假設的閾值(常見5%,即統計學意義“顯著”,significant),如果目前樣本統計量在零假設下出現的概率小於閾值,則拒絕零假設,承認備擇假設。
- 單樣本
- z檢驗
- t檢驗
- 雙樣本
- t檢驗
8.2 單樣本z檢驗
-
假設:要檢驗的統計量(近似)滿足正態分佈
-
常見用途:檢測總體平均值是否等於某個常量
-
python
零假設:復旦大學男生平均身高175cm
備擇假設:復旦大學男生平均身高不是175cmconda install statsmodels z, pval = statsmodels.stats.weightstats.ztest(X,values=175)
- X:樣本集
8.4 單樣本t檢驗
-
適用於樣本量較少(n<30)
-
自由度:樣本數量減去1
-
t分佈比正態分佈寬(不確定性更高)
-
python
零假設:復旦大學男生平均身高175cm
備擇假設:復旦大學男生平均身高不是175cmconda install scipy t,pval = scipy.stats.ttest_1samp(X,popmean=175)
- 比z檢驗更常用
8.5 雙樣本t檢驗
-
零假設:復旦大學和上海大學男生平均身高一樣
備擇假設:復旦大學和上海大學男生平均身高不一樣t, pval = scipy.stats.ttest_ind(X1,X2)
- 雙樣本t檢驗最常見的用法就是比較兩組樣本的平均值是否一致
可視化
-
sns.distplot(df['col1']) # 分佈圖 sns.regplot(x='col1',y='col3',data=df) # 連續變量間的相關性 sns.boxplot(x='col2',y='col3',data=df) # 離散變量與連續變量的相關性 # 熱力圖 info=['col1','col3','col5','col8'] sns.set(font_scale=0.7) # 設置字體大小 sns.heatmap(df[info].corr(), 相關性 annot=True, # 顯示參數值 vmin=0, # vmax=1)
9.6.1 相關性係數
-
皮爾遜係數
-
[-1,1],[負相關,正相關]
-
from scipy.stats.stats import pearsonr pearsonr(x,y)
-
df.corr()
-
交叉檢驗
-
多模型交叉檢驗
from sklearn.linear_model import LinearRegression from sklearn.ensemble import RandomForesRegressor from sklearn.model_selection import cross_val_score info=['col1','col3','col4','col5'] lr = LinearRegression() rf = RandomForestRegressor() models = [lr,rf] for model in models: scores = cross_val_score(model,df[info],df['col10'],cv=5,scoring='neg_mean_absolute_error') print(type(model).__name__,np.mean(scores))