pandas 数据清洗与异常值处理

一:检测与处理缺失值的操作

创建一个表格

import pandas as pd
import numpy as np

data = pd.DataFrame({
    "goods":["苹果","香蕉","芒果","猕猴桃","榴莲"],
    "price":[3.5, 2, np.NAN, 3, np.NAN],
    "num":[np.NAN, 41, 20, 12, np.NAN]
})
  1. isnull

判断元素时空值,如果是空值返回True,不是空值则返回False

# 判断df中的元素是否为空,返回一个bool类型的df
print(data.isnull())

# 结果
   goods  price    num
0  False  False   True
1  False  False  False
2  False   True  False
3  False  False  False
4  False   True   True
# 计算空值个数
print(data.isnull().sum())

# 结果
goods    0
price    2
num      2
dtype: int64
  1. notnull

判断元素不是空值的方法,如果是空值返回False,不是空值返回True

# 判断df中的元素是否不为空,返回一个bool类型的df
print(data.notnull())

# 结果
   goods  price    num
0   True   True  False
1   True   True   True
2   True  False   True
3   True   True   True
4   True  False  False
# 计算非空值个数
data.notnull().sum()  # 相当于data.count

# 结果
goods    5
price    3
num      3
dtype: int64
  1. fillna

填充空值的方法

格式:fillna({“列索引”:“修改值”,…})

参数:

limit,限制修改的个数,默认为None值,修改全部

inplace,是否在原表上修改,默认为False,不在原表修改,有返回值

# 填充每一列的第一个空值
res = data.fillna({"price":4,"num":0},limit=1,inplace=False)
print(res)

# 结果
  goods  price   num
0    苹果    3.5   0.0
1    香蕉    2.0  41.0
2    芒果    4.0  20.0
3   猕猴桃    3.0  12.0
4    榴莲    NaN   NaN
  1. dropna

how:为any时表示有空则删,为all时全为空才删除

thresh:阈值,当这一行的非空数目小于thresh值时进行删除

subset:指定字段进行判断后删除

# 删除含有空值的行
res2 = data.dropna(axis=0,how="any")
print(res2)

# 结果
  goods  price   num
1    香蕉    2.0  41.0
3   猕猴桃    3.0  12.0

# 如果price和num这两列的值都为空时则删除这一行数据
res2 = data.dropna(subset=["price","num"],axis=0,how="all")
print(res2)

# 结果
  goods  price   num
0    苹果    3.5   NaN
1    香蕉    2.0  41.0
2    芒果    NaN  20.0
3   猕猴桃    3.0  12.0

二:处理缺失值方法

插值法

  • 线性插值:要求x,y之间满足线性关系,即满足y = kx + b

    只能在规定的x范围内插值

    import numpy as np
    from scipy.interpolate import interpld
    
    # y = (x+1) * 2
    x = np.array([0,1,2,3,5])
    y = np.array([2,4,6,8,12])
    Linear1 = interp1d(x,y,kind="linear")
    print(Linear1([4]))  # 此处传入的参数只能在x的范围内
    print(Linear1([4.5]))  # 可传入小数,因为它是先推导表达式,然后传值进行计算的
    
    # 结果
    [10.]
    [11.2]
    
  • 多项插值的方法:利用已知的值,拟合一个多项式(拉格朗日插值,牛顿插值)

    from scipy.interpolate import lagrange
    
    # y1 = 2 * (x1+1)**2,且在5和6的位置上缺失两个值
    x1 = [0,1,2,3,4,7,8,9]
    y1 = [2,8,18,32,50,128,162,200]
    Larg = lagrange(x1,y1)
    print(Larg([5,6]))
    
    # 结果
    [72. 98.]
    

    总结:用非线性函数拟合线性的数据是可以的,但是用线性函数拟合非线性的数据,结果会很差。

三:检测与处理重复值

  • 记录重复

    # 创建表格
    df = pd.DataFrame({
    	"name":["zs","ls","ww","zs"],
    	"id":[1,2,3,1],
    	"age":[12,15,12,12]
    })
    
    # 当二维表格不传入subset参数时,默认以整行为比较单位
    ret = df.drop_duplicates(subset=["name","age"])
    print(ret)
    
    # 结果
      name  id  age
    0   zs   1   12
    1   ls   2   15
    2   ww   3   12
    
  • 特征重复

    需要是连续型数值,通过相似度的方法判定两列值是否具有某种关系,得到的值的范围为-1~1,越靠近1则表示相关性越强

    参数:

    • method

      ​ pearson:皮尔森相关性系数

      ​ kendall:肯德尔相关性系数

      ​ spearman:斯皮尔曼相关性系数

    # 方法一
    ret = df[["id","age"]].corr(method="kendall")
    print(ret)
    
    
    # 结果
               id       age
    id   1.000000  0.258199
    age  0.258199  1.000000
    
    
    # 方法二
    ret = df[["id","age"]].corr(method="spearman")
    print(ret)
    
    # 结果
               id       age
    id   1.000000  0.272166
    age  0.272166  1.000000
    

    注:这个方法只能处理数值型,不能处理类别型。类型型特征之间是无法通过相关系数来计算相似度的。

  • 哑变量处理

    将类别型数据转化为数值型数据

    返回的数据类型是一个df矩阵,类似于一个稀疏矩阵,one-hot编码

    ret = pd.get_dummies(df["name"])
    print(ret)
    
    # 结果
       ls  ww  zs
    0   0   0   1
    1   1   0   0
    2   0   1   0
    3   0   0   1
    

四:异常值处理

异常值是指我们的数据中个别数值明显偏离其余数值的数据,也称为离群点

检测异常值就是检测数据中是否录入错误以及是否有不合理的数据

  • 3σ原则:[拉伊达准则]

    该法则就是假设一组检验数据只有随机误差,对原始数据进行计算处理得到标准差。按照一定的概率确定一个区间,认为误差超过这个区间就属于异常值。3σ原则仅适用于服从正态分布或者近似正态分布的数据。

    μ - 3 σ < x < μ + 3σ,为正常区间数据,此区间的概率值为0.9973

    # 创建表格
    df = pd.DataFrame({
        "name":["zs","ls","ww","zl","aq","xm"],
        "weight":[168,174,181,155,170,172]
        })
    
    # 定义3σ原则表达式
    min_mask = df["weight"] < (df["weight"].mean() - 3 *  df["weight"].std())
    max_mask = df["weight"] > (df["weight"].mean() + 3 * df["weight"].std())
    # 只要满足上诉表达式的任一个就为异常值,所以这里使用位与运算
    mask = min_mask | max_mask
    print(df.loc[mask,"weight"])
    
    # 结果
    # 没有不符合3σ表达式的值,即无异常值
    Series([], Name: weight, dtype: float64)
    
  • 根据项目场景自定义阈值范围

五:连续数据离散化

分析一个问题时,某些特征是连续的,比如:年龄

  • 等宽法

    尽力要求区间宽度是一致的,但是落到每个区间内的频数就不能保持一致的,用此方法更多的是关注区间的宽度。最终会得到一个一维数组

    参数:

    bins,表示区间,当bins中传入数值型的时候,表示区间的个数;当bins中传入列表时,为自定义分割的区间

    right=False,改变区间的封闭方向,由右改为左

    labels=[item1,item2,…],使用自定义的分箱名称,这样就不只显示数字了

    precision=n,整数自动分箱时的精度

    方法:

    ret.codes,显示数据在对应的区间索引

    ret.categories,显示分类区间的详细信息

    pd.value_counts(ret),显示各分段的数量

    # 创建表格
    df = df.DataFrame({
    	"name":["zs","ls","ww","zl","xm","lh"],
    	"age":[26,54,33,10,43]
    })
    
    # bins为整数型时,将年龄分为3个区间
    ret = pd.cut(df3["age"],bins = 3)
    
    # 结果
    0     (22.0, 38.0]
    1     (38.0, 54.0]
    2     (22.0, 38.0]
    3    (5.952, 22.0]
    4     (38.0, 54.0]
    5    (5.952, 22.0]
    Name: age, dtype: category
    Categories (3, interval[float64]): [(5.952, 22.0] < (22.0, 38.0] < (38.0, 54.0]]
    	
    
    # 自定义区间
    ret2 = pd.cut(df3["age"],bins=[0,20,40,60])
    print(ret2)
    
    # 结果
    0    (20, 40]
    1    (40, 60]
    2    (20, 40]
    3     (0, 20]
    4    (40, 60]
    5     (0, 20]
    Name: age, dtype: category
    Categories (3, interval[int64]): [(0, 20] < (20, 40] < (40, 60]]
    
  • 等频法

    尽力使得数据能够均匀落到每个区间

    参数:

    q:当q传入数值型时,为区间的个数;当q传入一个列表时,列表中必须为分位数,为自定义区间

    # q为数值型时,表示区间的个数
    ret3 = pd.qcut(df3["age"],q=3)
    print(ret3)
    
    # 结果
    0    (5.999, 29.5]
    1     (29.5, 54.0]
    2     (29.5, 54.0]
    3    (5.999, 29.5]
    4     (29.5, 54.0]
    5    (5.999, 29.5]
    Name: age, dtype: category
    Categories (2, interval[float64]): [(5.999, 29.5] < (29.5, 54.0]]
    
    # q传入一个列表,为自定义区间
    ret4 = pd.qcut(df3["age"],q=[0, 0.3, 1])
    print(ret4)
    
    # 结果
    (21.5, 54.0]     4
    (5.999, 21.5]    2
    Name: age, dtype: int64
    

    等频与等差的区别:

    ​ 传入一个整数型时,等宽会照数组中的最大值和最小值平均分成5份,即分为5个区间,等频是先划分出5个区间并保证区间内的值个数相等,在满足频数的条件下再设置每个区间的开头和结尾值;传入一个列表时,等宽中的列表值即是每个区间的开头和结尾值,而等频中,列表中的值确定的是每个区间的个数,然后根据区间的个数确定每个区间的开头和结尾值。

六:数据标准化

当样本数据中属性的量纲差别很大的时候,相似度的计算结果就会完全由数值大的属性支配。

  1. 离差标准化

    x` = (x-min) / (max-min)

    x`的范围:0~1

    缺点

    • 标准化的数据不能取值完全一样。如果取值完全一样,则分母为0,公式不成立。
    • 该方法完全取决于max和min值,当max或min值为异常值的时候,标准化不准确,可能出现趋于0的情况。
    import numpy as np
    import pandas as pd
    
    x = pd.Series([-10, 20, 15, 16, 18, 21, 12])
    def get_transform(x):
    	new_x = (x-x.min()) / (x.max()-x.min())
    	return new_x
    x.transform(get_transform)
    
  2. 标准差标准化

    x` = (x-u) / σ 【u:均值,σ:标准差】

    标准差标准化之后的数据满足:u = 0, σ=1

    x` 范围为:负无穷~正无穷

    import numpy as np
    import pandas as pd
    
    x = pd.Series([-10, 20, 15, 16, 18, 21, 12])
    def get_transform(x):
    	new_x = (x-x.mean()) / x.std()
    	return new_x
    x.transform(get_transform)
    
  3. 小数定标标准化

    x` = x / 10k

    x`的范围通常设定在 -1~1 之间

    k值的确定:k = np.ceil(np.log10(x.abs().max()))

    缺点

    • 当出现异常值时,就会出现较大的误差
    import numpy as np
    import pandas as pd
    
    x = pd.Series([-10, 20, 15, 16, 18, 21, 12])
    def get_transform(x):
    	k = np.ceil(np.log10(x.abs().max()))
    	return x/10**k
    x.transform(get_transform)
    

你可能感兴趣的:(Algorithm,python,数据分析,pandas,数据清洗,异常值处理)