libsvm中tools 中提供了一个一条龙式的程序 easy.py
出于兴趣对原码做了一些学习
if len(sys.argv) <= 1:
print('Usage: {0} training_file [testing_file]'.format(sys.argv[0]))
raise SystemExit
(1)sys.argv: 实现从程序外部向程序传递参数,实质是个list
sys.argv[0] --> py程序本身
(2)raise SystemExit --> 退出程序
也可以用下面的格式
raise SystemExit('......')
(3) .format 用于字符串的格式化。
{0} 即代表着sys.argv[0]会出现在{0}的位置上。这里理应就是easy.py
除了通过位置,还可以通过关键字或者字典进行映射。此外,.format还可以实现左右对齐,精度进制控制等
这种映射方式相对之前类C的%f方式有何优势?
大概是这样:
print('{0},{1},{0},{0}'.format('wyz','21')
映射看起来要灵活得多
小结:这一段是对参数个数的检查,如果参数个数只有一个,即只有 python easy.py ,就提示正确用法,并退出
is_win32 = (sys.platform == 'win32')
if not is_win32:
svmscale_exe = "../svm-scale"
svmtrain_exe = "../svm-train"
svmpredict_exe = "../svm-predict"
grid_py = "./grid.py"
gnuplot_exe = "/usr/bin/gnuplot"
else:
# example for windows
svmscale_exe = r"..\windows\svm-scale.exe"
svmtrain_exe = r"..\windows\svm-train.exe"
svmpredict_exe = r"..\windows\svm-predict.exe"
gnuplot_exe = r"c:\tmp\gnuplot\binary\pgnuplot.exe"
grid_py = r".\grid.py"
(1) sys.platform 返回操作系统名称,windows平台返回值是'win32'
(2) ./表示同级文件, ../表示上级文件,这里定义了几个执行文件的路径
assert os.path.exists(svmscale_exe),"svm-scale executable not found"
assert os.path.exists(svmtrain_exe),"svm-train executable not found"
assert os.path.exists(svmpredict_exe),"svm-predict executable not found"
assert os.path.exists(gnuplot_exe),"gnuplot executable not found"
assert os.path.exists(grid_py),"grid.py not found"
train_pathname = sys.argv[1]
assert os.path.exists(train_pathname),"training file not found"
file_name = os.path.split(train_pathname)[1]
scaled_file = file_name + ".scale"
model_file = file_name + ".model"
range_file = file_name + ".range"
(1) os.path.exists()函数用来检验给出的路径是否真地存在
(2) assert 断言函数 用法
assert expression [, arguments]
如果expression 为假,就会输出后面这一句
(3) sys.argv[1] --> 等待training 的data集
if len(sys.argv) > 2:
test_pathname = sys.argv[2]
file_name = os.path.split(test_pathname)[1]
assert os.path.exists(test_pathname),"testing file not found"
scaled_test_file = file_name + ".scale"
predict_test_file = file_name + ".predict"
这一段检查参数是否包含测试文件名
cmd = '{0} -s "{1}" "{2}" > "{3}"'.format(svmscale_exe, range_file, train_pathname, scaled_file)
print('Scaling training data...')
Popen(cmd, shell = True, stdout = PIPE).communicate()
cmd = '{0} -svmtrain "{1}" -gnuplot "{2}" "{3}"'.format(grid_py, svmtrain_exe, gnuplot_exe, scaled_file)
print('Cross validation...')
f = Popen(cmd, shell = True, stdout = PIPE).stdout
这一段是最为难懂的
(1)cmd定义了一个字符串 svmscale_exe -s "range_file" "train_pathname" > "scaled_file"
(2)Popen 是subprocess模块中定义的一个类
实际创建了一个子进程。其中shell=True, 而 args 是字符串,它将作为命令行字符串通过shell 执行。
Popen的communicate方法使父进程与子进程能够交流,二元组 (stdoutdata, stderrdata) 分别表示从标准出和标准错误中读出的数据。
而设置stdout = Pipe ,则使得父进程可以接受子进程返回的数据。communicate会阻塞父进程直至子进程结束。
详细参见Baby_Ape的博客 非常详细易懂
小结而言,这段代码首先创建子进程scale训练集;然后创建子进程利用grid.py和gnuplot来寻找最好的svm参数
line = ''
while True:
last_line = line
line = f.readline()
if not line: break
c,g,rate = map(float,last_line.split())
看起来f是grid.py 输出的文件。 c,g 是SVM的参数,rate则是结果
(1)readline() 方法用于从文件读取整行,包括 "\n" 字符 用法:fileObject.readline();
(2)if not line:break 读到空行就退出
(3).split 分隔符默认为所有的空字符,包括空格、换行(\n)、制表符(\t)等。 用法: str.split(str="", num=string.count(str))
num为分割次数
(4)map函数,将分割出的内容都变为float,然后赋给c,g,rate。处在float位置的通常是某个函数
print('Best c={0}, g={1} CV rate={2}'.format(c,g,rate))
cmd = '{0} -c {1} -g {2} "{3}" "{4}"'.format(svmtrain_exe,c,g,scaled_file,model_file)
print('Training...')
Popen(cmd, shell = True, stdout = PIPE).communicate()
print('Output model: {0}'.format(model_file))
利用最好的参数对训练集再次进行训练
if len(sys.argv) > 2:
cmd = '{0} -r "{1}" "{2}" > "{3}"'.format(svmscale_exe, range_file, test_pathname, scaled_test_file)
print('Scaling testing data...')
Popen(cmd, shell = True, stdout = PIPE).communicate()
cmd = '{0} "{1}" "{2}" "{3}"'.format(svmpredict_exe, scaled_test_file, model_file, predict_test_file)
print('Testing...')
Popen(cmd, shell = True).communicate()
print('Output prediction: {0}'.format(predict_test_file))
如果有测试集,利用最优参数对测试集进行预测
总结: easy.py (1)参数,文件路径等进行检查
(2)建立子进程scale数据,利用grid.py找到最优参数
(3)利用最优参数跑训练集和测试集,并输出结果