缺失值类型
对缺失值进行填充,或者删除特征列
当单个特征列的缺失值占总样本数的20即以上时,删除该列,否则填充,填充有自定义填充,统计值填充。
定义数据集
import numpy as np
import pandas as pd
# 构造数据
def dataset():
col1 = [1, 2, 3, 4, 5, 6, 7, 8, 9,10]
col2 = [3, 1, 7, np.nan, 4, 0, 5, 7, 12, np.nan]
col3 = [3, np.nan, np.nan, np.nan, 9, np.nan, 10, np.nan, 4, np.nan]
y = [10, 15, 8, 12, 17, 9, 7, 14, 16, 20]
data = {'feature1':col1, 'feature2':col2, 'feature3':col3, 'label':y}
df = pd.DataFrame(data)
return df
data = dataset()
data
feature1 | feature2 | feature3 | label | |
---|---|---|---|---|
0 | 1 | 3.0 | 3.0 | 10 |
1 | 2 | 1.0 | NaN | 15 |
2 | 3 | 7.0 | NaN | 8 |
3 | 4 | NaN | NaN | 12 |
4 | 5 | 4.0 | 9.0 | 17 |
5 | 6 | 0.0 | NaN | 9 |
6 | 7 | 5.0 | 10.0 | 7 |
7 | 8 | 7.0 | NaN | 14 |
8 | 9 | 12.0 | 4.0 | 16 |
9 | 10 | NaN | NaN | 20 |
删除缺失值大于50%的列的函数
def delete_feature(df):
N = df.shape[0] # 样本数
'''先用count数出每一个特征的非空数据数量, 返回的是series,转化成dataframe,不过是\
竖着的,在转置一下'''
no_nan_count = df.count().to_frame().T
del_feature, save_feature = [], [] # 设置删除列表和保存列表
''' 非空count的特征列转化成列表,不用转的话是index类型,但也可以运行'''
for col in no_nan_count.columns.tolist():
'''no_nan_count[col]返回的是序列类型,.values返回的是一个只有一个元素的列表
这里也可以直接用序列的索引df.count()[col],可以直接取出值,不用转来转去'''
loss_rate = (N - no_nan_count[col].values[0])/N # 缺失率
# print(loss_rate)
if loss_rate > 0.5: # 缺失率大于 50% 时,将这一维特征删除
del_feature.append(col)
else:
save_feature.append(col)
return del_feature, df[save_feature]
del_feature, df11 = delete_feature(data)
print(del_feature)
df11
删除样本的函数
DataFrme.dropna(axis=0,how=’any’,thresh=None,subset=None,inplace=False)参数:
axis: 默认axis=0。0为按行删除,1为按列删除
how: 默认 ‘any’。 ‘any’指带缺失值的所有行/列;’all’指清除一整行/列都是缺失值的行/列
thresh: int,保留含有int个非nan值的行
subset: 删除特定列中包含缺失值的行或列
inplace: 默认False,即筛选后的数据存为副本,True表示直接在原数据上更改
def delete_sample(df):
df_ = df.dropna()
return df_
delete_sample(df11)
填充特征列
- 对于特征的缺失值,可以根据缺失值所对应的那一维特征的统计值来进行填充。统计值一般泛指平均值、中位数、众数、最大值、最小值等,具体使用哪一种统计值要根据具体问题具体分析。
注意事项:当特征之间存在很强的类别信息时,需要进行类内统计,效果比直接处理会更好。比如在填充身高时,需要先对男女进行分组聚合之后再进行统计值填充处理(男士的一般平均身高1.70,女士一般1.60)。df方法填充
```python均值填充
print(df11.mean())
‘’’ 返回一个序列 feature1 5.500 feature2 4.875 label 12.800 dtype: float64’’’
df11.fillna(df11.mean()) # 分别把对应的均值填充到各个列中
中位数填充
print(df11.median()) df11.fillna(df11.median())
众数填充
print(df11.mode())
由于众数可能会存在多个,因此返回的是序列而不是一个值
所以在填充众数的时候,我们可以 df11[‘feature’].mode()[0],可以取第一个众数作为填充值
def mode_fill(df): for col in df.columns.tolist(): # 可以不加tolist ‘’’isnull()返回一个序列,空值被置换成True,sum()求True的个数,序列的话返回int 也可以直接用describe的循环来判断是否有缺失值’’’ if df[col].isnull().sum() > 0: # 有缺失值就进行众数填充 df[col] = df[col].fillna(df11[col].mode()[0])
return df
mode_fill(df11)
最大最小值填充
df11.fillna(df11.max()) df11.fillna(df11.min())
<a name="L1uEk"></a>
## 调包填充(记这个好了)
```python
from sklearn.impute import SimpleImputer
mean_impute = SimpleImputer(strategy='mean') # median、most_frequent
'''整体填充会变成一个大数组,需要重新转换成DataFrame,所以可以用循环一列一列填充'''
df11 = pd.DataFrame(mean_impute.fit_transform(df11),columns=['feature1','feature2','label'])
df11