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