一:检测与处理缺失值的操作
创建一个表格
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]
})
判断元素时空值,如果是空值返回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
判断元素不是空值的方法,如果是空值返回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
填充空值的方法
格式: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
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个区间并保证区间内的值个数相等,在满足频数的条件下再设置每个区间的开头和结尾值;传入一个列表时,等宽中的列表值即是每个区间的开头和结尾值,而等频中,列表中的值确定的是每个区间的个数,然后根据区间的个数确定每个区间的开头和结尾值。
六:数据标准化
当样本数据中属性的量纲差别很大的时候,相似度的计算结果就会完全由数值大的属性支配。
-
离差标准化
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)
-
标准差标准化
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)
-
小数定标标准化
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)