导言
在某次工作项目中需要使用libsvm格式的数据训练xgboost模型,得到模型之后再验证模型打分的时候使用csv格式数据,发现用csv文件的预测值和libsvm格式数据的预测值对不上,经过一系列尝试最终解决了这个问题。
导致问题的原因:Dmatrix对不同存储方式的数据的处理方式不一致。
接下来是问题复现和问题解决的过程:
生成模拟libsvm格式数据
1.首先是准备复现问题的数据
## xgboost == 2.0.0
feature_list = [1,4,5,6,7] ##特征编号
import random
def gen_data(file_path,cnt):
with open(file_path,"w") as f:
for i in range(cnt):
##label 0,1,2
f.write(str(random.randint(0,2)) + " ")
##写特征
for j in range(len(feature_list)):
if j == len(feature_list) - 1:
f.write(str(feature_list[j]) + ":" + str(random.randint(1, 1000)) + "\n")
else:
f.write(str(feature_list[j]) + ":" + str(random.randint(1, 1000)) + " ")
2.生成数据
gen_data("train.libsvm",1000)
gen_data("test.libsvm",100)
3.使用生成的libsvm格式数据训练模型
import xgboost as xgb
from xgboost import DMatrix
test = DMatrix("test.libsvm?format=libsvm")
train = DMatrix("train.libsvm?format=libsvm")
params = {'objective': 'multi:softprob', 'eta': 0.1, 'gamma': 1.0,
'min_child_weight': 0.1, 'max_depth': 6,'num_class':3}
num_round = 100
model = xgb.train(params,train, num_round,evals=[(test, 'validation')])
model.save_model("demo.model")
4.复现问题
将libsvm格式数据转换为csv格式的代码
import pandas as pd
def lib2csv(file_path):
tmp_dic = {}
for i in feature_list:
tmp_dic[i] = list()
with open(file_path,"r") as f:
for i in f.readlines():
tmp = i.split(" ")[1:]
for j in tmp:
key,value = j.split(":")
tmp_dic[int(key)].append(int(value))
df = pd.DataFrame()
for i in feature_list:
df[i] = tmp_dic[i]
ans = file_path + ".csv"
df.to_csv(ans,index = None,header = None)
gen_data("valid.libsvm",100)
直接使用libsvm格式数据预测
##直接使用libsvm格式数据预测
a = DMatrix("valid.libsvm?format=libsvm")
model.predict(a)
使用转换后的csv格式数据预测
lib2csv("valid.libsvm")
df = pd.read_csv("valid.libsvm.csv",names = feature_list)
b = DMatrix(df)
model.predict(b)
转换后的数据如下所示:
转化后的数据与libsvm数据完全一致
lib预测结果:
csv预测结果:
此时发现同样的数据,但存储格式不同预测出来的结果不一致。
解决问题方法
对csv格式的数据进行特征补全,让其特征编号连续(特征名称和特征值可以随意填充)
values = [-1 for i in range(100)]
df.insert(loc=0, column=0, value=values)
df.insert(loc=2, column=2, value=values)
df.insert(loc=3, column=3, value=values)
c = DMatrix(df)
model.predict(c)
填充之后,预测结果正确