一·随机森林的算法填充
python
import pandas as pd
import matplotlib.pyplot as plt
import fill_data
data = pd.read_excel("矿物数据.xls")
data = data[data['矿物类型'] != 'E'] # 删除特殊的类别E。整个数据集中只存在1个E数据。
null_num = data.isnull()
null_total = null_num.sum() # 检测每列中的缺失值
X_whole = data.drop('矿物类型', axis=1).drop('序号', axis=1) # 获取全部特征数据
y_whole = data.矿物类型 # 获取全部标签数据
label_dict = {"A": 0, "B": 1, "C": 2, "D": 3} # 将数据中的中文标签转换为字符
encoded_labels = [label_dict[label] for label in y_whole]
y_whole = pd.Series(encoded_labels, name='矿物类型') # 将列表转换为Pandas Series
# 数据中存在大量字符串数值、\、空格等异常数据。字符串数值直接转换为float,\和空格转换为nan
for column_name in X_whole.columns:
X_whole[column_name] = pd.to_numeric(X_whole[column_name], errors='coerce')
#pd.to_numeric()函数尝试将参数中的数据转换为数值类型。如果转换失败,它会引发一个异常,
#设置errors='coerce',会将无法转换的值设置为NaN。
"""数据标准化:Z标准化"""
from sklearn.preprocessing import StandardScaler
scaler = StandardScaler()
X_whole_Z = scaler.fit_transform(X_whole)
X_whole = pd.DataFrame(X_whole_Z, columns=X_whole.columns) # Z标准化处理后为numpy数据,这里再转换回pandas数据
'''数据集的切分'''
from sklearn.model_selection import train_test_split
x_train_w, x_test_w, y_train_w, y_test_w = \
train_test_split(X_whole, y_whole, test_size=0.3, random_state=50000)
'''数据中存在空缺,进行6种方法进行填充'''
## 1、只保留完整数据集
# x_train_fill,y_train_fill = fill_data.cca_train_fill(x_train_w,y_train_w)#调用自己写的implement_data.py
# 测试集的填充
# x_test_fill,y_test_fill = fill_data.cca_test_fill(x_train_fill, y_train_fill, x_test_w, y_test_w)#调用
#2、使用平均值的方法对数据进行填充
# x_train_fill,y_train_fill = fill_data.mean_train_fill(x_train_w,y_train_w)
# 测试集的填充
# x_test_fill,y_test_fill = fill_data.mean_test_fill(x_train_fill, y_train_fill, x_test_w, y_test_w)
##3、使用中位数的方法对数据进行填充
# x_train_fill,y_train_fill = fill_data.median_train_fill(x_train_w,y_train_w)#调用自己写的implement_data
##测试集的填充
# x_test_fill,y_test_fill = fill_data.median_test_fill(x_train_fill, y_train_fill, x_test_w, y_test_w)
##4、使用众数的方法对数据进行填充
# x_train_fill,y_train_fill = fill_data.mode_train_fill(x_train_w,y_train_w)#调用自己写的implement_data.p
###测试集的填充
# x_test_fill,y_test_fill = fill_data.mode_test_fill(x_train_fill, y_train_fill, x_test_w, y_test_w)#调
# 5、线性回归算法实现训练数据集、测试数据集的填充
x_train_fill,y_train_fill = fill_data.lr_train_fill(x_train_w,y_train_w)#调用自己写的#implement_data.py文
# 测试集的填充
#x_test_fill,y_test_fill = fill_data.lr_test_fill(x_train_fill, y_train_fill, x_test_w, y_test_w)#调用自
## 6、随机森林算法实现训练数据集、测试数据集的填充
x_train_fill,y_train_fill = fill_data.rf_train_fill(x_train_w,y_train_w)
# 测试集的填充
x_test_fill,y_test_fill = fill_data.rf_test_fill(x_train_fill, y_train_fill, x_test_w, y_test_w)#调用自己
'''smote算法实现数据集的拟合,解决样本不均衡'''
from imblearn.over_sampling import SMOTE
oversampler = SMOTE(k_neighbors=1, random_state=42)#数据对象
os_x_train, os_y_train = oversampler.fit_resample(x_train_fill, y_train_fill)#人工拟合的只是训练集。
'''数据保存为excel文件'''
data_train = pd.concat([os_y_train,os_x_train],axis=1).sample(frac=1, random_state=4)#sample()方法用于从 `DataFrame` 中随机抽取行,`frac` 表示抽取行的比例。
data_test = pd.concat([y_test_fill,x_test_fill],axis=1)#测试集不用传入模型训练,无需打乱顺序。
data_train.to_excel(r'.//temp_data//训练数据集[平均值填充的数据].xlsx', index=False)
data_test.to_excel(r'.//temp_data//测试数据集[平均值填充的数据].xlsx', index=False)
python
from sklearn.ensemble import RandomForestRegressor
'''---------------------随机森林算法实现训练数据集、测试数据集的填充---------------------'''
def rf_train_fill(train_data, train_label):
'''使用随机森林算法填充训练数据集中的缺失值'''
train_data_all = pd.concat([train_data, train_label], axis=1)
train_data_all = train_data_all.reset_index(drop=True)#data数据行号存在混乱(因随机抽取70%的数据作为训练集导致),进行重置
train_data_X = train_data_all.drop('矿物类型', axis=1)
null_num = train_data_X.isnull().sum() # 查看每个特征中存在空数据的个数
null_num_sorted = null_num.sort_values(ascending=True)#将空数据的类别从小到大进行排序
filling_feature = []
for i in null_num_sorted.index:
filling_feature.append(i)
if null_num_sorted[i] !=0:
X = train_data_X[filling_feature].drop(i, axis=1)
y = train_data_X[i]
row_numbers_mg_null = train_data_X[train_data_X[i].isnull()].index.tolist()#获取空数据对应行号
X_train = X.drop(row_numbers_mg_null) # 非空的数据作为训练数据集
y_train = y.drop(row_numbers_mg_null) # 非空的标签作为训练标签
X_test = X.iloc[row_numbers_mg_null] # 空的数据作为测试数据集
regr = RandomForestRegressor(n_estimators=100, random_state=42) # 创建随机森林回归模型
regr.fit(X_train, y_train) # 训练模型
y_pred = regr.predict(X_test) # 使用模型进行预测
train_data_X.loc[row_numbers_mg_null,i] = y_pred#loc和iloc的区别:iloc[行号.列号] loc[行名,列名],例如iloc[3,4]
print('完成训练数据集中的\'{}\'列数据的填充'.format(i))
return train_data_X, train_data_all.矿物类型
def rf_test_fill(train_data, train_label, test_data, test_label):
'''使用随机森林算法对测试数据集中缺失的数据进行填充,主要是基于这样一个思想:
根据已经填充后的训练数据集建立模型,来补充空缺的测试数据集。'''
train_data_all = pd.concat([train_data, train_label], axis=1)
train_data_all = train_data_all.reset_index(drop=True)
test_data_all = pd.concat([test_data, test_label], axis=1)
test_data_all = test_data_all.reset_index(drop=True)
train_data_X = train_data_all.drop('矿物类型', axis=1)
test_data_X = test_data_all.drop('矿物类型', axis=1)
null_num = test_data_X.isnull().sum()
null_num_sorted = null_num.sort_values(ascending=True)
filling_feature = []
for i in null_num_sorted.index:
filling_feature.append(i)
if null_num_sorted[i] !=0:
X_train = train_data_X[filling_feature].drop(i, axis=1)
y_train = train_data_X[i]
X_test = test_data_X[filling_feature].drop(i, axis=1)
row_numbers_mg_null = test_data_X[test_data_X[i].isnull()].index.tolist()#获取空数据对应行号
X_test = X_test.iloc[row_numbers_mg_null] # 空的数据作为测试数据集
regr = RandomForestRegressor(n_estimators=100, random_state=42) # 创建随机森林回归模型
regr.fit(X_train, y_train) # 训练模型
y_pred = regr.predict(X_test) # 使用模型进行预测
test_data_X.loc[row_numbers_mg_null,i] = y_pred
print('完成测试数据集中的\'{}\'列数据的填充'.format(i))
return test_data_X, test_data_all.矿物类型
rf_train_fill
函数(训练集填充)
python
运行
python
from sklearn.ensemble import RandomForestRegressor
- 导入随机森林回归器,用于构建预测缺失值的模型(因为缺失值是连续数值,所以用回归而非分类)
python
运行
python
'''---------------------随机森林算法实现训练数据集、测试数据集的填充---------------------'''
def rf_train_fill(train_data, train_label):
- 定义
rf_train_fill
函数,参数是训练特征(train_data
,对应整体代码中的x_train_w
)和训练标签(train_label
,对应y_train_w
) - 功能:用随机森林填充训练集中的缺失值,返回填充后的训练特征和标签
python
运行
python
train_data_all = pd.concat([train_data, train_label], axis=1)
- 合并训练特征和标签(按列合并,
axis=1
),得到包含特征 + 标签的完整训练数据 - 原因:后续填充时可能需要保持特征与标签的对应关系(虽然填充逻辑中未直接用标签,但保留完整结构更安全)
python
运行
python
train_data_all = train_data_all.reset_index(drop=True)
- 重置数据的索引(
drop=True
表示删除原有索引,不保留为新列) - 原因:之前用
train_test_split
划分数据集时,索引可能被打乱(不是连续的 0,1,2...),重置后方便后续按行索引操作
python
运行
python
train_data_X = train_data_all.drop('矿物类型', axis=1)
- 从合并数据中删除标签列(
矿物类型
),得到纯特征数据(train_data_X
) - 因为填充操作只针对特征,不涉及标签
python
运行
python
null_num = train_data_X.isnull().sum()
- 统计每个特征列的缺失值数量(
isnull()
判断是否为 NaN,sum()
按列求和) - 例如:若某列有 10 个 NaN,
null_num
中该列对应的值就是 10
python
运行
python
null_num_sorted = null_num.sort_values(ascending=True)
- 对缺失值数量按升序 排序(
ascending=True
) - 核心逻辑:先处理缺失值少的特征(用其他更完整的特征预测它),再处理缺失值多的特征(避免用已填充过的、误差可能较大的特征做过多预测)
python
运行
python
filling_feature = []
- 创建空列表,用于记录 "已经处理过的特征"
- 作用:后续用这些已处理的特征作为输入,预测当前需要填充的特征
python
运行
python
for i in null_num_sorted.index:
- 遍历排序后的特征名称(按缺失值从少到多的顺序)
python
运行
python
filling_feature.append(i)
- 将当前遍历的特征加入 "已处理列表"
- 即使该特征没有缺失值,也会加入(作为后续其他特征的预测输入)
python
运行
python
if null_num_sorted[i] !=0:
- 只处理有缺失值的特征(无缺失值的特征跳过填充逻辑)
python
运行
python
X = train_data_X[filling_feature].drop(i, axis=1)
- 构建 "预测输入特征集":从已处理的特征中,去掉当前要填充的特征
i
- 例如:当前填充特征是
Fe
,已处理特征有SiO2
、Al2O3
、Fe
,则X
就是SiO2
和Al2O3
的数据(用它们预测Fe
的缺失值)
python
运行
python
y = train_data_X[i]
- 定义 "预测目标":当前要填充的特征
i
的所有值(包括非缺失和缺失的)
python
运行
python
row_numbers_mg_null = train_data_X[train_data_X[i].isnull()].index.tolist()
- 找到特征
i
中所有缺失值所在的行索引,并转为列表 - 例如:
Fe
列在第 5、10、15 行有缺失,则这个列表就是[5,10,15]
python
运行
python
X_train = X.drop(row_numbers_mg_null)
- 构建模型的训练输入:从
X
中删除缺失值所在的行(只保留特征i
非缺失的行) - 这些行的特征
i
有真实值,可用于训练模型
python
运行
python
y_train = y.drop(row_numbers_mg_null)
- 构建模型的训练目标:从
y
中删除缺失值所在的行(只保留特征i
的非缺失值)
python
运行
python
X_test = X.iloc[row_numbers_mg_null]
- 构建模型的测试输入:从
X
中提取缺失值所在的行(这些行的特征i
需要被预测填充)
python
运行
python
regr = RandomForestRegressor(n_estimators=100, random_state=42)
- 创建随机森林回归模型:
n_estimators=100
表示用 100 棵树,random_state=42
固定随机种子(保证结果可复现)
python
运行
python
regr.fit(X_train, y_train)
- 用非缺失数据训练模型:学习输入特征
X_train
与目标y_train
(特征i
的真实值)的关系
python
运行
python
y_pred = regr.predict(X_test)
- 预测缺失值:用训练好的模型,对缺失行的输入特征
X_test
进行预测,得到特征i
缺失值的预测结果
python
运行
python
train_data_X.loc[row_numbers_mg_null,i] = y_pred
- 填充缺失值:将预测结果
y_pred
赋值给特征i
的缺失行(通过行索引定位) loc
按 "行索引 + 列名" 定位,确保准确填充到缺失位置
python
运行
python
print('完成训练数据集中的\'{}\'列数据的填充'.format(i))
- 打印日志:提示当前特征
i
的填充已完
python
运行
python
return train_data_X, train_data_all.矿物类型
- 函数返回:填充后的训练特征(
train_data_X
)和对应的标签(train_data_all.矿物类型
) - 对应整体代码中接收的
x_train_fill, y_train_fill
rf_test_fill
函数(测试集填充)
python
运行
python
def rf_test_fill(train_data, train_label, test_data, test_label):
- 定义
rf_test_fill
函数,参数包括:填充后的训练特征(train_data
)、训练标签(train_label
)、原始测试特征(test_data
,对应x_test_w
)、测试标签(test_label
,对应y_test_w
) - 功能:用训练集的数据训练模型,填充测试集中的缺失值,返回填充后的测试特征和标签
python
运行
python
train_data_all = pd.concat([train_data, train_label], axis=1)
train_data_all = train_data_all.reset_index(drop=True)
- 合并填充后的训练特征和标签,重置索引(同训练集填充逻辑,统一格式)
python
运行
python
test_data_all = pd.concat([test_data, test_label], axis=1)
test_data_all = test_data_all.reset_index(drop=True)
- 合并原始测试特征和标签,重置索引(处理测试集的索引混乱问题)
python
运行
python
train_data_X = train_data_all.drop('矿物类型', axis=1)
test_data_X = test_data_all.drop('矿物类型', axis=1)
- 从合并数据中分离出训练集特征(
train_data_X
)和测试集特征(test_data_X
)(均删除标签列)
python
运行
python
null_num = test_data_X.isnull().sum()
null_num_sorted = null_num.sort_values(ascending=True)
- 统计测试集每个特征的缺失值数量,并按升序排序(同训练集逻辑,先处理缺失少的)
python
运行
python
filling_feature = []
for i in null_num_sorted.index:
filling_feature.append(i)
if null_num_sorted[i] !=0:
- 逻辑同训练集:创建 "已处理特征列表",遍历测试集特征(按缺失值从少到多),只处理有缺失值的特征
python
运行
python
X_train = train_data_X[filling_feature].drop(i, axis=1)
- 构建模型的训练输入:使用训练集的已处理特征 (而非测试集自身),去掉当前要填充的特征
i
- 核心:测试集填充的模型完全基于训练集,避免数据泄露(测试集信息不能参与模型训练)
python
运行
python
y_train = train_data_X[i]
- 构建模型的训练目标:训练集 中特征
i
的所有值(此时训练集已填充完整,无缺失)
python
运行
python
X_test = test_data_X[filling_feature].drop(i, axis=1)
row_numbers_mg_null = test_data_X[test_data_X[i].isnull()].index.tolist()
X_test = X_test.iloc[row_numbers_mg_null]
- 构建模型的测试输入:从测试集的已处理特征中,提取当前特征
i
缺失值所在行的数据(用于预测填充)
python
运行
python
regr = RandomForestRegressor(n_estimators=100, random_state=42)
regr.fit(X_train, y_train)
y_pred = regr.predict(X_test)
test_data_X.loc[row_numbers_mg_null,i] = y_pred
print('完成测试数据集中的\'{}\'列数据的填充'.format(i))
- 逻辑同训练集:用训练集数据训练模型,预测测试集缺失值并填充,打印日志
python
运行
python
return test_data_X, test_data_all.矿物类型
二·模型算法
- 函数返回:填充后的测试特征(
test_data_X
)和对应的标签(test_data_all.矿物类型
) - 对应整体代码中接收的
x_test_fill, y_test_fill
python
import pandas as pd
from sklearn import metrics
# 数据提取
train_data = pd.read_excel(r'./temp_data/训练数据集[平均值填充的数据].xlsx')
train_data_x = train_data.iloc[:, 1:] # 训练数据集的特征
train_data_y = train_data.iloc[:, 0] # 训练数据集的测试标签label
test_data = pd.read_excel(r'./temp_data/测试数据集[平均值填充的数据].xlsx')
test_data_x = test_data.iloc[:, 1:] # 测试数据集的特征
test_data_y = test_data.iloc[:, 0] # 测试数据集的测试标签label
result_data = {} # 用来保存后面6种算法的结果
'''#####################逻辑回归LR算法实现代码###########################'''
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import GridSearchCV # 网格搜索
param_grid = {
'penalty': ['l1', 'l2', 'elasticnet', 'none'], # 正则化类型
'C': [0.001, 0.01, 0.1, 1, 10, 100], # 正则化强度的倒数
'solver': ['newton-cg', 'lbfgs', 'liblinear', 'sag', 'saga'], # 优化算法
'max_iter': [100, 200, 500], # 最大迭代次数
'multi_class': ['auto', 'ovr', 'multinomial'],
} # 多分类策略(注意: 'none' 惩罚时不支持 'multinomial')
# 注意: 'penalty' 为 'none' 时, 'C' 将被忽略。而且, 不是所有的求解器都支持所有的正则化选项。
# 另外, 当使用 'liblinear' 求解器时, 'multi_class' 只能为 'ovr'。
# 因此, 在实际使用中, 可能需要针对特定的求解器调整参数网格。
# 注意: 上述参数网格在实际应用中可能需要调整, 因为某些参数组合可能不支持·或不稳定。
# 例如, 当使用L1正则化时, 'solver' 参数就不能使用 'newton-cg', 'sag' 和 'lbfgs'。
# 同样地, 当 'penalty' 是 'none' 时, 'C' 参数将不起作用。
# 创建Logistic回归模型实例
logreg = LogisticRegression()
grid_search = GridSearchCV(logreg, param_grid, cv=5) # 创建GridSearchCV对象
grid_search.fit(train_data_x, train_data_y) # 在训练集上执行网格搜索
print("Best parameters set found on development set:") # 输出最佳参数
print(grid_search.best_params_)
...
"""建立最优模型"""
LR_result = {} # 用来保存训练之后的结果。
lr = LogisticRegression(C=0.001, max_iter=100, penalty='none', solver='newton-cg') # 逻辑回归的参
lr.fit(train_data_x, train_data_y)
'''测试结果【含训练数据集的测试 + 测试数据集的测试】'''
train_predicted = lr.predict(train_data_x) # 训练数据集的预测结果
print('LR的train:\n', metrics.classification_report(train_data_y, train_predicted))
test_predicted = lr.predict(test_data_x) # 测试数据集的预测结果
print('LR的test:\n', metrics.classification_report(test_data_y, test_predicted)) # 打印测试数据集的
a = metrics.classification_report(test_data_y, test_predicted, digits=6) # digits表示保留有效位数
b = a.split()
LR_result['recall_0'] = float(b[6]) # 添加类别为0的召回率
LR_result['recall_1'] = float(b[11]) # 添加类别为1的召回率
LR_result['recall_2'] = float(b[16]) # 添加类别为2的召回率
LR_result['recall_3'] = float(b[21]) # 添加类别为3的召回率
LR_result['acc'] = float(b[25]) # 添加accuracy的结果
result_data['LR'] = LR_result # result_data是总体的结果,
print('lr结束')
分别确立确立特征x和y标签
python
import pandas as pd
from sklearn import metrics
# 数据提取
train_data = pd.read_excel(r'./temp_data/训练数据集[平均值填充的数据].xlsx')
train_data_x = train_data.iloc[:, 1:] # 训练数据集的特征
train_data_y = train_data.iloc[:, 0] # 训练数据集的测试标签label
test_data = pd.read_excel(r'./temp_data/测试数据集[平均值填充的数据].xlsx')
test_data_x = test_data.iloc[:, 1:] # 测试数据集的特征
test_data_y = test_data.iloc[:, 0] # 测试数据集的测试标签label

网格搜索------核心还是交叉验证
python
from sklearn.model_selection import GridSearchCV # 网格搜索
param_grid = {
'penalty': ['l1', 'l2', 'elasticnet', 'none'], # 正则化类型
'C': [0.001, 0.01, 0.1, 1, 10, 100], # 正则化强度的倒数
'solver': ['newton-cg', 'lbfgs', 'liblinear', 'sag', 'saga'], # 优化算法
'max_iter': [100, 200, 500], # 最大迭代次数
'multi_class': ['auto', 'ovr', 'multinomial'],
} # 多分类策略(注意: 'none' 惩罚时不支持 'multinomial')
# 注意: 'penalty' 为 'none' 时, 'C' 将被忽略。而且, 不是所有的求解器都支持所有的正则化选项。
# 另外, 当使用 'liblinear' 求解器时, 'multi_class' 只能为 'ovr'。
# 因此, 在实际使用中, 可能需要针对特定的求解器调整参数网格。
# 注意: 上述参数网格在实际应用中可能需要调整, 因为某些参数组合可能不支持·或不稳定。
# 例如, 当使用L1正则化时, 'solver' 参数就不能使用 'newton-cg', 'sag' 和 'lbfgs'。
# 同样地, 当 'penalty' 是 'none' 时, 'C' 参数将不起作用。
logreg = LogisticRegression()
grid_search = GridSearchCV(logreg, param_grid, cv=5) # 创建GridSearchCV对象
grid_search.fit(train_data_x, train_data_y) # 在训练集上执行网格搜索
print("Best parameters set found on development set:") # 输出最佳参数
print(grid_search.best_params_)
GridSearchCV网格搜索算法内部就是交叉验证
C参数是惩罚因子,
python
'''测试结果【含训练数据集的测试 + 测试数据集的测试】'''
train_predicted = lr.predict(train_data_x) # 训练数据集的预测结果
print('LR的train:\n', metrics.classification_report(train_data_y, train_predicted))
test_predicted = lr.predict(test_data_x) # 测试数据集的预测结果
print('LR的test:\n', metrics.classification_report(test_data_y, test_predicted)) # 打印测试数据集的
a = metrics.classification_report(test_data_y, test_predicted, digits=6) # digits表示保留有效位数
b = a.split()
预测好的结果,然后比较
python
LR_result['recall_0'] = float(b[6]) # 添加类别为0的召回率
LR_result['recall_1'] = float(b[11]) # 添加类别为1的召回率
LR_result['recall_2'] = float(b[16]) # 添加类别为2的召回率
LR_result['recall_3'] = float(b[21]) # 添加类别为3的召回率
LR_result['acc'] = float(b[25]) # 添加accuracy的结果
result_data['LR'] = LR_result # result_data是总体的结果,
print('lr结束')
输入字典表格,返回到这个位置来
python
LR_result = {} # 用来保存训练之后的结果。
然后保存文件
python
import json # 数据格式,网络传输。保存提取json类型的数据。
# 使用 'w' 模式打开文件,确保如果文件已存在则会被覆盖,
result = {}
result['mean fill'] = result_data
with open(r'temp_data/平均值填充result.json', 'w', encoding='utf-8') as file:
# 使用 json.dump() 方法将字典转换为 JSON 格式并写入文件,JSON 一般来是字典
json.dump(result, file, ensure_ascii=False, indent=4)
json方便网络传输,任何编程语言都可以读取