在我们进行数据分析时,通常会遇到各种数据缺失的情况,针对这种情况我们该如何进行填补呢?
1、人工填补
该方法仅适用于小数据集,受个人因素影响。
2、平均值填补
对某一列的缺失值,采用该列的平均值填充
df.fillna(method=a.mean(),inplace=True)
此处重点讲解一下fillna的参数,后面不做说明
fillna(value=None, method=None, axis=None, inplace=False, limit=None, downcast=None, **kwargs)
#value:固定值,可以用固定数字、均值、中位数、众数等,此外还可以用字典,series等形式数据;
#method:填充方法,'bfill','backfill','pad','ffill'
#axis: 填充方向,默认0和index,还可以填1和columns
#inplace:在原有数据上直接修改
#limit:填充个数,如1,每列只填充1个缺失值
3、临近值填补
对每一列的缺失值,采用临近位置的数据进行填充。
#使用每列缺失值前面的值进行填充(按相应列填充,按照相应index前后填充)
df.fillna(method='ffill',inplace=True)
df.fillna(method='pad',inplace=True)
#使用每列缺失值后面的值进行填充(按相应列填充,按照相应index前后填充)
df.fillna(method='backfill',inplace=True)
df.fillna(method='bfill',inplace=True)
#使用每列缺失值前面的值进行填充(按相邻列填充,按照相应columns前后填充)
df.fillna(method='ffill',inplace=True,axis=1)
df.fillna(method='pad',inplace=True,axis='columns')
#使用每列缺失值后面的值进行填充(按相邻列填充,按照相应columns前后填充)
df.fillna(method='backfill',inplace=True,axis=1)
df.fillna(method='bfill',inplace=True,axis='columns')
对每一列的缺失值,采用临近位置上下两个值的平均值来填充
#上下两个值的平均值进行填充
df=df.fillna(df.interpolate())
#在此详细介绍下interpolate函数的参数:'nearest', 'zero', 'slinear', 'quadratic', 'cubic', 'spline', 'barycentric', 'polynomial'
4、中位数填补
对每列的数值采用中位数进行填补
df.fillna(df.median(),inplace=True)
5、众数填补
对每列数值采用众数填补
df.fillna(df.mode(),inplace=True)
6、回归填补
对于有缺失值的特征值,将已知特征值代入模型来估计未知特征值,以此估计值来进行填充,该填充方法适用于缺失值为定量的数据类型。
from sklearn.experimental import enable_iterative_imputer
from sklearn.impute import IterativeImputer
#data为缺失的数据集
imp = IterativeImputer(max_iter=10, random_state=0)
imp.fit(data)
print(np.round(imp.transform(data)))
7、热平台填补
热平台插补又被称为热卡插补,是从每一缺失数据的估计分布抽取插补值来取代缺失值,使用回答单元中的抽样分布作为抽样分布是常见的方法。热卡插补包括随机抽样插补、分层热卡插补、最近距离热卡插补和序贯热卡插补。
随机抽样插补。缺失值为Missing Completely at Random,MCAR,即完全随机缺失的情况下,对某个确实字段进行简单随机抽样、限制对回答单元的使用次数、对回答单元进行排序并进行抽样;
分层热卡填补。首先按照某些辅助变量对y进行分层,然后对分层的数据进行热卡插补;
最近距离热卡插补。利用辅助变量,定义一个测量单元间距离的函数,在变量y的无回答单元临近的回答单元中,选择满则设定的距离条件的辅助变量中的单元所对应的变量y的回答单元作为插补值。由于使用较为复杂的距离函数,很难对插补后的均值和方差等估计量的性质进行考察;
序贯热卡填充。基于最近距离热卡插补来实现的,首先对数据分层,在每层中按照选定的某个辅助变量排序,并在其前后相邻的10个数据中,找到是的设定的某一个距离函数的值达到最小的单元,使用该单元对应的变量y的回答单元作为插补值。
8、冷平台填补
从以前的调查中或其他信息来源中获得,如历史数据。
9、极大似然估计
缺失类型为随机缺失的条件下,假设模型对于完整的样本是正确的,那么通过观测数据的边际分布可以对未知参数进行极大似然估计。这种方法也被称为忽略缺失值的极大似然估计,对于极大似然的参数估计实际中常采用的计算方法是期望值最大化。该方法适用于大样本。
假设我们有一个观测数据集,其中包含一些缺失值。我们希望估计缺失值,使得整个数据集的似然最大。通常,我们会基于已观测到的数据和一个合适的概率分布来构建似然函数。然后,通过优化似然函数,我们可以找到使得观测数据出现的概率最大的缺失值估计。
下面是一个简单的示例,使用极大似然估计填补缺失值。在这个例子中,我们假设数据服从正态分布,然后使用正态分布的均值和方差进行估计。
import pandas as pd
import numpy as np
from scipy.stats import norm
from sklearn.impute import SimpleImputer
def mle_imputation(df, target_col):
"""
使用极大似然估计填补缺失值
Parameters:
- df: DataFrame, 包含缺失值的数据帧
- target_col: str, 要填补的目标列
Returns:
- df_filled: DataFrame, 填补后的数据帧
"""
df_filled = df.copy()
# 提取有缺失值的数据和没有缺失值的数据
missing_data = df_filled[df_filled[target_col].isnull()]
observed_data = df_filled.dropna(subset=[target_col])
# 使用已观测数据的均值和方差进行极大似然估计
mu, sigma = norm.fit(observed_data[target_col])
# 用估计的均值和方差填补缺失值
imputer = SimpleImputer(strategy='constant', fill_value=mu)
df_filled[target_col] = imputer.fit_transform(df_filled[[target_col]])
return df_filled
# 示例数据
data = {
'feature1': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
'feature2': [2, 4, 1, 5, 3, 6, 8, 7, 10, 9],
'target': [10, 20, np.nan, 40, 50, 60, np.nan, 80, 90, 100]
}
df = pd.DataFrame(data)
# 指定目标列进行填补
target_column = 'target'
# 使用极大似然估计填补缺失值
df_filled = mle_imputation(df, target_column)
# 打印填补后的数据框
print(df_filled)
10、k均值聚类法
该方法又被称为K最近距离邻法。实现方式为:采用k-means聚类将所有样本进行聚类划分,然后再通过划分的种类的均值对各自类中的缺失值进行填补。
import pandas as pd
import numpy as np
from sklearn.cluster import KMeans
def kmeans_imputation(df, target_col, feature_cols, n_clusters=3):
"""
使用K均值聚类法进行缺失值填补
Parameters:
- df: DataFrame, 包含缺失值的数据帧
- target_col: str, 要填补的目标列
- feature_cols: list, 用于聚类的特征列
- n_clusters: int, 聚类数目
Returns:
- df_filled: DataFrame, 填补后的数据帧
"""
df_filled = df.copy()
# 提取有缺失值的数据和没有缺失值的数据
missing_data = df_filled[df_filled[target_col].isnull()]
observed_data = df_filled.dropna(subset=[target_col])
if not missing_data.empty:
# 使用K均值聚类法对已观测数据进行聚类
kmeans = KMeans(n_clusters=n_clusters, random_state=42)
df_filled.loc[df_filled[target_col].notnull(), 'cluster'] = kmeans.fit_predict(observed_data[feature_cols])
# 计算每个簇的均值
cluster_means = df_filled.groupby('cluster')[target_col].mean()
# 将每个缺失值所属的簇的均值填充到相应的缺失位置
cluster_assignments = kmeans.predict(missing_data[feature_cols])
df_filled.loc[df_filled[target_col].isnull(), 'cluster'] = cluster_assignments
# 将缺失值的簇均值映射回原始数据框
df_filled.loc[df_filled[target_col].isnull(), target_col] = \
df_filled.loc[df_filled[target_col].isnull()].apply(
lambda row: cluster_means[row['cluster']] if np.isnan(row[target_col]) else row[target_col],
axis=1
)
# 移除聚类结果列
df_filled.drop('cluster', axis=1, inplace=True)
return df_filled
# 示例数据
data = {
'feature1': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
'feature2': [2, 4, 1, 5, 3, 6, 8, 7, 10, 9],
'target': [10, 20, np.nan, 40, 50, 60, np.nan, 80, 90, 100]
}
df = pd.DataFrame(data)
# 指定目标列和特征列进行填补
target_column = 'target'
feature_columns = ['feature1', 'feature2']
# 使用K均值聚类法进行缺失值填补
df_filled = kmeans_imputation(df, target_column, feature_columns, n_clusters=3)
# 打印填补后的数据框
print(df_filled)
11、随机森林填补
采用随机森林来对缺失值进行拟合。
from sklearn import ensemble
from sklearn.preprocessing import LabelEncoder
def set_missing(df, estimate_list, miss_col):
"""使用随机森林回归预测缺失值,并填充到原始数据帧中。
Parameters:
- df: DataFrame, 要处理的数据帧
- estimate_list: list, 用来估计缺失值的字段列表
- miss_col: str, 缺失字段名称
Returns:
- df: DataFrame, 处理后的数据帧
"""
col_list = estimate_list + [miss_col]
# 创建处理用的数据帧
process_df = df.loc[:, col_list]
# 使用 LabelEncoder 对字符串特征进行编码
class_le = LabelEncoder()
for i in estimate_list:
process_df.loc[:, i] = class_le.fit_transform(process_df.loc[:, i].astype(str))
# 分成已知该特征和未知该特征两部分
known = process_df[process_df[miss_col].notnull()].values
known[:, -1] = class_le.fit_transform(known[:, -1].astype(str))
unknown = process_df[process_df[miss_col].isnull()].values
# X为特征属性值
X = known[:, :-1]
# y为结果标签值
y = known[:, -1]
# 使用随机森林回归进行拟合
rfr = ensemble.RandomForestRegressor(random_state=1, n_estimators=200, max_depth=4, n_jobs=-1)
rfr.fit(X, y)
# 用得到的模型进行未知特征值预测
predicted = rfr.predict(unknown[:, :-1]).round(0).astype(int)
predicted = class_le.inverse_transform(predicted)
# 用得到的预测结果填补原缺失数据
df.loc[df[miss_col].isnull(), miss_col] = predicted
return df
# 示例数据
data = {
'Feature1': ['A', 'B', 'C', 'A', 'B', 'C', 'A', 'B', 'C', 'A'],
'Feature2': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
'Target': [10, 20, np.nan, 40, 50, 60, np.nan, 80, 90, 100]
}
df = pd.DataFrame(data)
# 使用优化后的函数填补缺失值
df_filled = set_missing(df, ['Feature1', 'Feature2'], 'Target')
# 打印填补后的数据框
print(df_filled)
12、趋势得分法
趋势得分法(Trend Imputation)是一种常见的缺失值填补方法,它基于时间序列数据的趋势进行估计。以下是使用趋势得分法进行确实值填补的一般步骤:
理解数据和缺失模式:首先,了解你的数据集,确定缺失值的分布和模式。检查数据是否有明显的趋势,例如季节性变化或逐渐增长/减小的趋势。
创建时间序列: 如果你的数据包含时间信息,将数据按照时间排序并创建时间序列。确保时间序列是均匀的,即时间点之间的间隔是一致的。
计算趋势:使用合适的方法(例如线性回归、移动平均线等)计算数据的趋势。这可以通过拟合模型到已知数据点并预测缺失值来完成。
计算趋势得分:对于每个缺失值,使用趋势模型预测该时间点的值,并计算实际观测值与预测值之间的差异,即趋势得分。这个得分表示缺失值相对于趋势的偏差。
填补缺失值: 使用趋势得分调整趋势预测值,然后将这个调整后的值用于填补缺失值。例如,如果趋势得分为正,表示实际值高于趋势预测值,则填补值可以设定为趋势预测值加上趋势得分。
验证填补效果:评估使用趋势得分法填补后的数据,检查是否合理并符合实际趋势。可以使用可视化工具或其他指标来进行验证。
下面是一个简单的Python代码示例,使用线性回归进行趋势拟合和趋势得分法的填补:
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
def fill_missing_values(df, timestamp_col='timestamp', value_col='value'):
# 确保按时间排序
df = df.sort_values(timestamp_col)
# 提取时间序列和数值列
timestamps = df[timestamp_col].astype('int64').values.reshape(-1, 1)
values = df[value_col].values.reshape(-1, 1)
# 创建并拟合线性回归模型
model = LinearRegression()
valid_data = df.dropna(subset=[value_col]) # 排除缺失值
model.fit(valid_data[[timestamp_col]].astype('int64').values.reshape(-1, 1), valid_data[[value_col]])
# 预测缺失值
missing_values = df[df[value_col].isnull()]
missing_timestamps = missing_values[timestamp_col].astype('int64').values.reshape(-1, 1)
predicted_values = model.predict(missing_timestamps)
# 将预测值放回到原始数据框的缺失位置
df_filled = df.copy() # 避免修改原始数据
df_filled.loc[df_filled[value_col].isnull(), value_col] = predicted_values.flatten()
return df_filled
# 创建示例数据
data = {
'timestamp': pd.date_range(start='2022-01-01', end='2022-01-10', freq='D'),
'value': [1, 2, np.nan, 4, 5, 6, np.nan, 8, 9, 10]
}
df = pd.DataFrame(data)
# 使用优化后的函数填补缺失值
df_filled = fill_missing_values(df)
# 打印填补后的数据框
print(df_filled)
13、马尔科夫链蒙德洛夫法
马尔科夫链蒙特卡洛(MCMC)方法是一种贝叶斯统计方法,可以用于估计复杂模型的未知参数,其中蒙特卡洛指的是通过随机抽样来近似计算。马尔科夫链是一种随机过程,具有马尔科夫性质,即未来状态只依赖于当前状态而不依赖于过去状态。Metropolis-Hastings算法是一种基于马尔科夫链蒙特卡洛的采样方法,常用于贝叶斯推断。
在缺失值填补的情境中,你可以使用马尔科夫链蒙特卡洛方法来从缺失值的后验分布中进行采样。
14、随机回归填补
随机回归填补是一种通过随机抽样来填补缺失值的方法。该方法利用回归模型来估计缺失值,并在模型的预测分布中进行随机抽样以填充缺失值。以下是一个简单的 Python 代码示例,使用线性回归模型进行随机回归填补:
import pandas as pd
import numpy as np
from sklearn.linear_model import LinearRegression
def random_regression_imputation(df, target_col, feature_cols):
"""
使用随机回归填补缺失值
Parameters:
- df: DataFrame, 包含缺失值的数据帧
- target_col: str, 要填补的目标列
- feature_cols: list, 用于预测目标的特征列
Returns:
- df_filled: DataFrame, 填补后的数据帧
"""
df_filled = df.copy()
# 提取有缺失值的数据和没有缺失值的数据
missing_data = df_filled[df_filled[target_col].isnull()]
observed_data = df_filled.dropna(subset=[target_col])
# 划分特征和目标
X_observed = observed_data[feature_cols].values.reshape(-1, len(feature_cols))
y_observed = observed_data[target_col].values.reshape(-1, 1)
X_missing = missing_data[feature_cols].values.reshape(-1, len(feature_cols))
# 创建线性回归模型并拟合
model = LinearRegression()
model.fit(X_observed, y_observed)
# 预测缺失值
predicted_values = model.predict(X_missing)
# 在预测分布中进行随机抽样
random_samples = np.random.normal(loc=predicted_values, scale=np.std(y_observed), size=predicted_values.shape)
# 将随机抽样的值填充回原始数据框
df_filled.loc[df_filled[target_col].isnull(), target_col] = random_samples.flatten()
return df_filled
# 示例数据
data = {
'feature1': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
'feature2': [2, 4, 1, 5, 3, 6, 8, 7, 10, 9],
'target': [10, 20, np.nan, 40, 50, 60, np.nan, 80, 90, 100]
}
df = pd.DataFrame(data)
# 指定目标列和特征列进行填补
target_column = 'target'
feature_columns = ['feature1', 'feature2']
# 使用随机回归填补缺失值
df_filled = random_regression_imputation(df, target_column, feature_columns)
# 打印填补后的数据框
print(df_filled)
15、增加虚拟变量
在原有数据集上增加一个字段。判断特征值是否有缺失值来定义一个新的二分类变量