【Python數據處理專題】數據處理和分析的基本流程

儒冠多誤身

2019.04.20個人總結

  • 第一步:備份源數據到其他盤符、硬盤、u盤、網盤等
  1. 需求分析
  2. 數據提取
  3. 數據清洗
  4. 數據分析
  5. 報告撰寫
  6. 報告分享
  7. 投入應用收集反饋

文章目錄

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:一行都不保留

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)]
    
切比雪夫定理
  • 前提(無),經驗公式:
  1. 至少有75%的數據,位於平均數2個標準差範圍內
  2. 至少有89%的數據,位於平均數3個標準差範圍內
  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 分佈分析

  1. 定性字段分佈:柱狀圖 + 餅圖
  2. 定量字段分佈:直方圖

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 累計頻率-帕累託分析指標

  • 帕累託分析

    1. 先由大到小排序

    2. 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 可視化

  1. 定量字段分佈

    • 柱狀圖
    • 堆積柱狀圖
    • 百分比柱狀圖
    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))
    
  2. 定性字段分佈

    # 柱狀圖
    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 數據建模

  1. 模型選擇
  2. 模型測試
  3. 迭代優化
  4. 模型加載

5.2.1 線性迴歸(初學者)

5.2.2 聚類模型(初學者)

5.2.3

6. 可視化

1 分析圖表

單維度

  • 柱狀圖
  • 折線圖
  • 餅圖
  • 散點圖

多維度

  • 熱力圖
  • 箱線圖
  • 矩陣
  • 散點圖

空間圖表

關係圖表

2 動態交互

3 商業智能

  • BDP
  • Tableau
  • power BI
  • 脈策數據-Datamap

7. 業務理解

8 驗證型分析

  • 基本概念
    • 隨機變量
      • 離散隨機變量:取值可能性有限
      • 連續隨機變量:有無限個可能取值的隨機變量
    • 概率分佈
      • 連續隨機變量概率分佈
        • 概率密度函數
    • 假設檢驗
    • P-value
      • 5%
      • 1%
      • 0.1%
    • 中心極限定理
      • 大量相互獨立的隨機變量,其均值的分佈以正態分佈爲極限

8.1 假設檢驗基本流程

  1. 提出零假設(我們希望推翻的結論),及備擇假設(我們希望證明的結論)
  2. 在零假設的前提下,推斷當前樣本統計量出現的概率
    • 統計量可符合不同分佈,及對應不同的檢驗方法
  3. 設定一個拒絕零假設的閾值(常見5%,即統計學意義“顯著”,significant),如果目前樣本統計量在零假設下出現的概率小於閾值,則拒絕零假設,承認備擇假設。
  • 單樣本
    • z檢驗
    • t檢驗
  • 雙樣本
    • t檢驗

8.2 單樣本z檢驗

  • 假設:要檢驗的統計量(近似)滿足正態分佈

  • 常見用途:檢測總體平均值是否等於某個常量

  • python
    零假設:復旦大學男生平均身高175cm
    備擇假設:復旦大學男生平均身高不是175cm

    conda install statsmodels
    
    z, pval = statsmodels.stats.weightstats.ztest(X,values=175)
    
    • X:樣本集

8.4 單樣本t檢驗

  • 適用於樣本量較少(n<30)

  • 自由度:樣本數量減去1

  • t分佈比正態分佈寬(不確定性更高)

  • python
    零假設:復旦大學男生平均身高175cm
    備擇假設:復旦大學男生平均身高不是175cm

    conda 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,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))
    
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章