我正在将一些命令行工具命令转移到可重用的Python脚本。但是,我似乎无法理解LibSVM的Python实现。这是安装了LibSVM库的CLI命令(Linux):
svm-scale -l 0 -u 1 -r models/feats.range input.feats > feats.scaled
svm-predict feats.scaled models/feats.model feats.pred
示例输入文件(input.feats)
,其中UNK是要预测的标签,如下所示。 (旁注我发现在Windows上测试时,'UNK'作为任意值是不允许的,需要传递一个整数,所以libsvm/tools/checkdata.py
告诉我。我不明白为什么。 Linux完全没有问题。)
UNK 1:4.458333333333333 2:24.0 3:0.20833333333333334 4:8.333333333333334 5:29.166666666666668 6:87.5 7:0.5 8:0.5 9:0.16666666666666666 10:0.16666666666666666 11:4.0 12:4.0 13:0.19047619047619047 14:0.041666666666666664 15:0.041666666666666664 16:1.0 17:1.0 18:0.047619047619047616 19:0.2916666666666667 20:0.25 21:7.0 22:6.0 23:0.2857142857142857 29:0.125 30:0.041666666666666664 31:3.0 32:1.0 33:0.047619047619047616
第一个问题是,我似乎无法找到一种方法来实现svm-scale
具有较低(-l
)和较高(-u
)绑定的给定参数模型({{ 1}})和输入文件。官方LibSVM实现的Python branch微不足道。我not the only one with this question。 This answer建议使用-r
,即使这适用于简单的sklearn.preprocessing
或-1,1
缩放,我也希望根据以前的参数进行扩展 - 正如{ 0,1
的CLI界面中的{1}}(恢复)参数。我还没有找到解决方案。 如何使用以前保存的参数来扩展数据?此类参数文件-r
的示例如下所示:
svm-scale
即使这是成功的,我也不完全确定在加载模型和预测标签时如何进行。 以下内容是否正确?(改编自示例here。)
feats.range
下面给出了模型x
0 1
1 3.88936170212766 6.346938775510204
2 7.34375 32.625
3 0.1188118811881188 0.4538461538461538
4 3.3003300330033 34.61538461538461
5 18.13471502590674 67.34693877551021
6 43.38235294117647 78.46153846153847
7 0.4794117647058824 0.7286821705426356
8 0.2713178294573644 0.5205882352941176
9 0.1808873720136519 0.5045045045045045
10 0.1148936170212766 0.4144144144144144
11 1.875 12.83333333333333
12 0.84375 10.33333333333333
13 0.217948717948718 0.6125
14 0.02006688963210702 0.1769230769230769
15 0.02006688963210702 0.1538461538461539
16 0.1875 4
17 0.15625 2.857142857142857
18 0.04477611940298507 0.2264150943396226
19 0.0796812749003984 0.2603550295857988
20 0.04682274247491638 0.2
21 1.5 5.777777777777778
22 0.8125 5
23 0.08490566037735849 0.3459119496855346
24 0 0.101010101010101
25 0 0.08856088560885608
26 0 2.444444444444445
27 0 2.25
28 0 0.1437125748502994
29 0.06825938566552901 0.1923076923076923
30 0.03105590062111801 0.1203703703703704
31 0.59375 5.5
32 0.3125 3
33 0.05220883534136546 0.1857142857142857
34 0 0.01818181818181818
35 0 0.5833333333333334
36 0 0.01558441558441558
37 0 0.5
38 0 0.01481481481481482
39 0 0.25
42 0 0.007281553398058253
43 0 0.1818181818181818
的一个示例。
from libsvm.svm import *
from libsvm.svmutil import *
model = svm_load_model('models/feats.model')
# Given the scaled features
pred = svm.libsvm.predict(feats_scaled, model)
答案 0 :(得分:0)
我相信您可以使用sklearn的sklearn.preprocessing.MinMaxScaler
来完成所需的行为,可以根据MinMaxScaler(feature_range=(0, 1), copy=True)
扩展每个功能是所需的范围。这是通过设置feature_range来实现的。在计算方面,每个要素的最大值和最小值是在fit
期间计算的,并在predict
期间使用。
svm-scale
的工作方式类似,在您建议的文件中保存了转换测试数据所需的缩放因子。在这里,首次调用svm-scale
时,每个要素都将在范围集中进行变换。 Scikit的缩放器提供了更大的灵活性,因为您可以使用不同的比例缩放其功能,但这可能是直观的。
当首先拟合训练数据然后预测测试数据时,scikit学习的变换器最好用于整个管道。您可以根据已经包含文件的情况来修改它们,但对于后一种情况,最好编写自己的缩放功能以获得更清晰的代码。例如,假设有文件feats.range
:
x
0 1
1 -1 1
2 2 18
以下函数将产生所需的输出。
data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
def svm_scale(X, path="feats.range", new_range = (0,1)):
f = open(path).read().splitlines()[2:]
f = np.array([x.split() for x in f]).astype(float)
my_min, my_max = f[:,1], f[:,2] # second/third col is the feat. mins/max
X_std = (X - my_min) / (my_max - my_min) # This brings at (0,1)
X_scaled = X_std * (new_range[1] - new_range[0]) + new_range[0] # Modifies min/max
return X_scaled
svm_scale(data) # returns array([[ 0., 0.],[ 0.25, 0.25],[ 0.5, 0.5 ], [1.,1.]])
答案 1 :(得分:0)
对不起,我在理解你在这里想要完成什么方面遇到了一些麻烦。
如果问题是"如何创建具有先前保存的特征权重的模型,那将更简单" OR "如何在此CLI中解决此特定的linux / Windows操作系统差异?"但你在评论中承认了这一点。
换句话说,如果我们使用scikit-learn,您已经拥有"每个功能相对缩放数据" ?在你的feat。范围例子中,第0列是特征索引,第1列是min,第2列是max?为什么不直接将缩放器的属性分配给已安装的分钟和最大值?
from sklearn.preprocessing import minMaxScaler
data = [[-1, 2], [-0.5, 6], [0, 10], [1, 18]]
scaler = MinMaxScaler()
scaler.transform(data)
scaler.scale_
返回array([ 0.5 , 0.0625])
但我们可以强迫它成为我们想要的任何东西,例如你的feats.range
from numpy import array
scaler.scale_ = array([12345, 54321]) #your values go here, I think?
scaler.scale_
返回array([12345, 54321])
如果我误解了道歉。
答案 2 :(得分:-1)
我对LibSVM的python API没有太多的经验,但是经过快速浏览后看起来似乎没有完整的命令行界面暴露给python。我在python API中找不到类似svm-scale
命令的任何东西,所以如果你真的想直接从python中做到这一点,那么看起来并不容易。
但是,从你的问题我得到的印象是运行命令行界面不一定是个问题,对吗?您可以安装并运行它,但更喜欢通过python自动化它。在这种情况下,我建议一个替代解决方案:使用python脚本的命令行界面。
例如,如果您要运行的命令是:
svm-scale -l 0 -u 1 -r models/feats.range input.feats > feats.scaled
我认为您可以使用以下python代码执行此操作:
import subprocess
subprocess.Popen(["svm-scale", "-l", "0", "-u", "1", "r", "models/feats.range", "input.feats", ">", "feats.scaled"])
注意:我不是100%确定指定输出文件的最后两个参数,也许subprocess.Popen()
调用的其他参数会更好(参见例如{{3 }})。我现在无法解决这个问题,但如果在我有时间进行实际测试之前你无法看到这个答案,可以稍后再进行编辑。
当然,此解决方案的另一个复杂之处在于,您的缩放功能最终会出现在文件中,而不是直接在python可访问的RAM中。那么,你将不得不写一些额外的代码来从文件中读取(或者svm_read_problem()
可能有效吗?不确定)。这个代码可能比尝试在python中重新实现svm-scale
功能要容易得多。