机器学习数据预处理代码汇总(最新更新20年3月1日)

这篇博客用一个pandas的DataFrame类型的数据为例,字段名为了不与任何第三方库混淆,我们叫他 dataframe

这篇博客没有长篇大论,就是希望能够让大家直接复制代码,然后把dataframe变量改为自己的dataframe变量后立竿见影得到预期结果。

博客大多数的用例dataframe,运行 dataframe.head() 可以看到类似这样的样子,它源于真实数据:

 tbi_valuetsibcibpibdibsimask
0871.38806.7315238547827680
1875.55807.6315168527877880
2874.53817.0415158587988100
3874.61817.5615068738128411
4870.45817.3915038898248641
import numpy as np
import pandas as pd

目录

1.描述性统计

1.1 数据基本信息

1.1.1 数据每个维度在计算机中的存储信息

1.1.2 数据的均值、标准差、分位点、最小值、最大值、方差

1.1.3 线性相关系数(皮尔森相关系数)

1.1.4 协方差矩阵

1.1.5 方差、中位数、众数

1.2 数值计算

1.2.1 本列所有值累加、累乘

2. 数据清洗

2.1 缺失值处理

2.1.1 确定值填充

2.1.2 参考当前列其他值填充

2.1.3 删除行

2.1.4 拉格朗日插值法填充

2.2 异常值处理

2.2.1 根据确定条件筛选数据

2.2.2 根据正态分布3∂原则异常值检测

2.2.3 Z-score 异常值检测

2.2.4 基于MAD的Z-score 异常值检测

2.2.5  数据倾斜处理(偏度)

2.3 非数值类型处理

2.3.1 字符特征离散化(one-hot编码)

2.4 时间序列

2.4.1 数据重采样

参考链接(感谢)


1.描述性统计

1.1 数据基本信息

1.1.1 数据每个维度在计算机中的存储信息

dataframe.info()
可以看到下面这个输出:
<class 'pandas.core.frame.DataFrame'>  # 表示是DataFrame类
RangeIndex: 1647 entries, 0 to 1646    # 行的index的值域
Data columns (total 7 columns):        # 一共有多少列
tbi_value    1647 non-null float64     # 下面是每一列的描述, 列名称 | 多少个非空的值 | 值类型
tsi          1647 non-null float64
bci          1647 non-null int64
bpi          1647 non-null int64
bdi          1647 non-null int64
bsi          1647 non-null int64
mask         1647 non-null int32
dtypes: float64(2), int32(1), int64(4) # 这是统计每个类型的总个数
memory usage: 83.7 KB                  # 这是内存占用,83.7k只占了非常少

1.1.2 数据的均值、标准差、分位点、最小值、最大值、方差

dataframe.describe()

可以看到下面这个输出:

 tbi_valuetsibcibpibdibsimask
count1647164716471647164716471647
mean720.862125645.3532971683.732241022.3752281016.361263850.6259870.477231
std176.724807129.814479862.435869373.262046360.824353220.2193280.499633
min328.8391.141612822952470
25%571.69533.89511047277516940
50%758.21640.1915449849668730
75%843.475750.16219813071204.59891
max1251.13979.4743292096233715621

其中 mean表示平均值,std为标准差,25%,50%,75%都是四分位点的值。

1.1.3 线性相关系数(皮尔森相关系数)

dataframe.corr()
 tbi_valuetsibcibpibdibsimask
tbi_value10.8528560.7634350.7369440.839170.841345-0.052892
tsi0.85285610.4732820.4570070.5357060.696586-0.060913
bci0.7634350.47328210.6934590.912690.633547-0.022511
bpi0.7369440.4570070.69345910.8876740.820403-0.005235
bdi0.839170.5357060.912690.88767410.832272-0.019859
bsi0.8413450.6965860.6335470.8204030.8322721-0.036575
mask-0.052892-0.060913-0.022511-0.005235-0.019859-0.0365751
max1251.13979.4743292096233715621

值域为 【-1,1】,越靠近-1则是负相关,越靠近1则是正相关,越靠近0则越无关;

1.1.4 协方差矩阵

dataframe.cov()
 tbi_valuetsibcibpibdibsimask
tbi_value31231.6575519565.75481116358.016348612.287753511.0541532743.63278-4.670225
tsi19565.7548116851.7989452987.0823822144.177925092.5887719913.7606-3.950785
bci116358.016352987.08238743795.6287223234.4268284017.9467120326.3567-9.700207
bpi48612.287722144.1779223234.4268139324.5554119553.734467436.73277-0.976263
bdi53511.0541525092.58877284017.9467119553.7344130194.213966132.73362-3.580166
bsi32743.6327819913.7606120326.356767436.7327766132.7336248496.55262-4.024317
mask-4.670225-3.950785-9.700207-0.976263-3.580166-4.0243170.249633
max1251.13979.4743292096233715621

这里协方差:大于0,就是正相关;小于0,就是负相关;等于0,就是完全无关;

绝对值越大,表示相关性的程度也越大(关联性越强),财务管理中有句话叫“协方差越小风险越低”,就是意味着这个变量对大局影响很小。

1.1.5 方差、中位数、众数

 方差:

dataframe.var()

中位数:

dataframe.median()

众数:

dataframe.mode()
 tbi_valuetsibcibpibdibsimask
0574.29742.416137275988990
1NaNNaN1935NaN1090944NaN

这样的结果表示bci、bdi、bsi这两个指标有2个众数,而其他的都是1个众数

1.1.6 查看一列中不同数值的个数

len(dataframe['列名'].unique())

这样可以直接显示dataframe这一列的不同种类的数量的个数,如果想要更详细的信息,可以直接使用:

dataframe['列名'].unique()

1.2 数值计算

1.2.1 本列所有值累加、累乘

 累加:

dataframe.cumsum()
 tbi_valuetsibcibpibdibsimask
0871.38806.7315238547827680
11746.931614.3630391706156915560
22621.462431.445542564236723660
33496.073248.9660603437317932071
44366.524066.3575634326400340712
.........................
16421184476.071060500.72771523168005416711101397796783
16431185177.571061101.912771999168095916718311398583784
16441185871.161061700.622772420168188116725431399372785
16451186563.861062298.682772819168284316732521400168785
16461187259.921062896.882773107168385216739471400981786

看输出的信息,大家可以看到这是一层层累加下去,第n行的值就是原始数据 第 n + (n-1) + (n-2) + ... + 1 行的值的总和。

累乘:

dataframe.cumprod()

与累加的输出类似,但累乘数值容易爆表,最后会输出 inf 表示已超出数据存储范围。

2. 数据清洗

2.1 缺失值处理

可以通过下面的代码得到缺失值的数量:

dataframe.isnull().sum()

也可通过简单的 .info() 来看缺失值的情况;

下面的代码可以得到 dataframe的缺失值占比情况:为0就表示没有缺失值

dataframe.isnull().sum()/len(dataframe)

缺失值在进行求和时,会被默认视为0

2.1.1 确定值填充

使用 0 填充缺失值:

dataframe.fillna(0,inplace=True)

也经常用这一列的平均值填充:

dataframe.fillna(dataframe.mean(),inplace=True)

2.1.2 参考当前列其他值填充

dataframe.fillna(method='pad',inplace=True) #参考前面值
dataframe.fillna(method='bfill',inplace=True) #参考后面值

比如dataframe矩阵长这个样子:

 012
01NaN2
19NaNNaN
234NaN
3567

如果使用 dataframe.fillna(method='pad') 就可以得到:可以看到每列的缺失值都根据前面出现的值进行填充

 012
01NaN2
19NaN2
2342
3567

如果使用 dataframe.fillna(method='bfill') 就可以得到:同理,每列缺失值都根据它之后最先出现的值填充

 012
0142
1947
2347
3567

2.1.3 删除行

dataframe.dropna(axis = 0,inplace=True)

这个可以直接删除有缺失值的行。

如果把axis=1,则会删除列,不建议这样做,除非这个维度的缺失值非常严重。

如果希望整行都缺失才删除,可以使用:

dataframe.dropna(axis=0, how='all', inplace=True)

2.1.4 拉格朗日插值法填充

使用拉格朗日插值法可以迅速填充缺失值,但是当连续缺失5个以上的数据,拉格朗日插值法会出现非常大的误差:

def lagrange_fill(dataframe,colname,k=5):
    def ployinterp_column(s, n, k=5):
        y = s[list(range(n-k, n)) + list(range(n+1, n+1+k))] #取数
        y = y[y.notnull()] #剔除空值
        return lagrange(y.index, list(y))(n) #插值并返回插值结果
    for i,index in enumerate(dataframe[colname][dataframe[colname].isnull()==True].index):
        dataframe[colname][index] = ployinterp_column(dataframe[colname],i)# todo 返回当前数据的位置
    return dataframe

调用方法是:

df = lagrange_fill(df,'KMI')
# df为dataframe格式的数据,'KMI'为有缺失值的一列的名称

2.2 异常值处理

当出现明显不合理的值时,需要剔除掉这些异常值

2.2.1 根据确定条件筛选数据

dataframe= dataframe[ (dataframe['列名1'] < 800) & (dataframe['列名2'] > 600)]

上面的例子筛选出了 dataframe中 列名1 指标 <800 且 列名2 指标 >600 的数据

这个套路可以根据确定的条件无限筛选出想要的数据,注意每个独立的小条件都要有括号 '( )'

2.2.2 根据正态分布3∂原则异常值检测

如果dataframe的某一列数据应该是呈现正态分布的,那么可以有如下筛选方案:

#.quantile(threshold)方法可以通过假定源数据服从正态分布,然后计算位于95%的点的值
#当 threshold = .95时:
# 95.449974的数据在平均数左右两个标准差的范围内
# 99.730020%的数据在平均数左右三个标准差的范围内
# 99.993666的数据在平均数左右三个标准差的范围内

def std_delete(dataframe,colname,threshold=.95):
    se = dataframe[colname]
    return dataframe[se < se.quantile(threshold)]

#剔除掉指定列名中存在异常值的那一行
dataframe = std_delete(dataframe , colname='列名')

如果threshold = .95筛选条件感觉不太合适,也可以使 threshold = .97 或是 .99 ,但如果.99还不行,那么就不能主观的认为是正态分布,应该做假设检验了,看看是不是其他分布。

2.2.3 Z-score 异常值检测

zscore和3∂原则的计算思路相同,计算公式是:

其中 xi 是一个数据点,μ 是所有点 xi 的平均值,δ 是所有点 xi 的标准偏差。

def zscore_check(dataframe,colname,threshold=3):
    se = dataframe[colname]
    zscore = (se - se.mean()) / (se.std())
    return dataframe[zscore.abs() < threshold]

dataframe = zscore_check(dataframe,'列名')

threshold 一般为 2.5 ,3.0 ,3.5

2.2.4 基于MAD的Z-score 异常值检测

MAD为(Mean Absolute Deviation,中位数绝对偏差),是单变量数据集中样本差异性的统计量,比标准差更有弹性,它的计算公式是:

在维基百科中有细致的推理过程:https://en.wikipedia.org/wiki/Median_absolute_deviation

根据推理,我们得到一个结果:MAD 约等于 0.6745*δ ,这个结论有利于编程,因此:

def zscore_mad_check(dataframe,colname,threshold=3.5):
    se = dataframe[colname]
    MAD = (se - se.median()).abs().median()
    zscore = ((se - se.median())* 0.6475 /MAD).abs()
    return dataframe[zscore < threshold]

dataframe= zscore_mad_check(dataframe,'列名')

同样的, threshold 一般设置为 2.5  3.0  3.5

2.2.5  数据倾斜处理(偏度)

使用下面的代码确认数据是否倾斜:

from scipy import stats

stats.mstats.skew(dataframe['列名']).data

如果值大于1,则证明存在倾斜;值越接近于0,越趋近于平缓,如果倾斜,则使用下面的代码处理:

dataframe['列名'] = np.log(dataframe['列名'])

也可以使用这段代码得到偏度大于1的列名,表示这些列需要额外注意:

def check_skew(dataframe):
    skew_attention = []
    for column in dataframe.columns:
        if (dataframe[column].dtype == 'int64') or (dataframe[column].dtype == 'float64'):
            skew = stats.mstats.skew(dataframe[column]).data
            if skew >= 1:
                skew_attention.append(column)
    return skew_attention

 

2.3 非数值类型处理

2.3.1 字符特征离散化(one-hot编码)

比如dataframe是这个样子:

 fc1fc2fc3
01a2
19NoneNaN
23b2
35a7
45c7

现在 fc2 需要整理一下(离散化):

dataframe= pd.get_dummies(dataframe,dummy_na=True,columns=['fc2'])
 fc1fc3fc2_afc2_bfc2_cfc2_nan
0121000
19NaN0001
2320100
3571000
4570010

原本是object类型,这样就可以很快的变成01类型加以区分,常用于有固定选项的特征中。

如果没有 “dummy_na = True”,dataframe中就不会有 “fc2_nan” 这一列;其他不变

也可以指定离散某一个数值型的特征:

# temp可以得到离散化 ‘fc1’ 这个特征的 dataframe
temp = pd.get_dummies(dataframe['fc1'],dummy_na=True)
# 把 dataframe与 temp 拼接起来并且删除已经被离散化的 ‘fc1’ 特征
dataframe= dataframe.join(temp).drop('fc1',axis = 1)

可以得到把 fc1 离散化的结果:

 fc2fc3fc1_1.0fc1_3.0fc1_5.0fc1_9.0fc1_nan
0a210000
1NoneNaN00010
2b201000
3a700100
4c70010 

2.4 时间序列

2.4.1 数据重采样

降采样:将时间线压缩

series.resample('M').sum()

这里'M'代表将时间变为以月份来记,之后的 .sum() 是对合并的数据的操作,也可以改为 .mean() 求均值。

升采样:将时间线拉长

series.resample('D').sum()

如果直接拉伸,会有很多NaN,因此升采样一般情况下需要考虑空值的填充

空值取前面的值:

series.resample('D').ffill()

空值取后面的值:

series.resample('D').bfill()

线性填充:

ts.resample('H').interpolate()

2.4.2 变异系数

from numpy import mean, std

# coefficient of variation
def cov(se):
    return mean(se)/std(se)

cov(dataframe['列名'])
 

 

 

参考链接(感谢)

pandas api:https://pandas.pydata.org/pandas-docs/stable/reference/index.html

sklearn api:https://scikit-learn.org/stable/modules/classes.html

Python数据分析之pandas统计分析:https://blog.csdn.net/A632189007/article/details/76176985

数据预处理与特征选择:https://blog.csdn.net/u010089444/article/details/70053104

总结:数据清洗的一些总结:https://blog.csdn.net/MrLevo520/article/details/77573757

异常值检测方法汇总:https://segmentfault.com/a/1190000015926584

用Python做单变量数据集的异常点分析:https://my.oschina.net/taogang/blog/279402

Minitab 18 支持:https://support.minitab.com/zh-cn/minitab/18/

 

如果有 错误 or 补充 or 代码解释 or 其他需求,请留言;

  • 18
    点赞
  • 105
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

呆萌的代Ma

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值