如何使用 Orange 对数据进行分层?
How to stratify data using Orange?
正在寻求 Orange 专家的帮助。
我有一个大约 600 万行的数据集。为了简单起见,我们将只考虑两列。一个是正十进制数,作为连续值导入。另一个是离散值(0 或 1),其中 1 与 0 的比率为 30:1。
我正在使用分类树(我将其标记为 'learner')来获取分类器。然后我尝试对我的数据集进行交叉验证,同时针对压倒性的 30:1 样本偏差进行调整。我已经尝试了几种变体来执行此操作,但无论我是否对数据进行分层,都会继续得到相同的结果。
下面是我的代码,我已经注释掉了我尝试过的各行代码(同时使用 True 和 False 值进行分层):
import Orange
import os
import time
import operator
start = time.time()
print "Starting"
print ""
mydata = Orange.data.Table("testData.csv")
# This is used only for the test_with_indices method below
indicesCV = Orange.data.sample.SubsetIndicesCV(mydata)
# I only want the highest level classifier so max_depth=1
learner = Orange.classification.tree.TreeLearner(max_depth=1)
# These are the lines I've tried:
#res = Orange.evaluation.testing.cross_validation([learner], mydata, folds=5, stratified=True)
#res = Orange.evaluation.testing.proportion_test([learner], mydata, 0.8, 100, store_classifiers=1)
res = Orange.evaluation.testing.proportion_test([learner], mydata, learning_proportion=0.8, times=10, stratification=True, store_classifiers=1)
#res = Orange.evaluation.testing.test_with_indices([learner], mydata, indicesCV)
f = open('results.txt', 'a')
divString = "\n##### RESULTS (" + time.strftime("%Y-%m-%d %H:%M:%S") + ") #####"
f.write(divString)
f.write("\nAccuracy: %.2f" % Orange.evaluation.scoring.CA(res)[0])
f.write("\nPrecision: %.2f" % Orange.evaluation.scoring.Precision(res)[0])
f.write("\nRecall: %.2f" % Orange.evaluation.scoring.Recall(res)[0])
f.write("\nF1: %.2f\n" % Orange.evaluation.scoring.F1(res)[0])
tree = learner(mydata)
f.write(tree.to_string(leaf_str="%V (%M out of %N)"))
print tree.to_string(leaf_str="%V (%M out of %N)")
end = time.time()
print "Ending"
timeStr = "Execution time: " + str((end - start) / 60) + " minutes"
f.write(timeStr)
f.close()
注意:可能看起来有语法错误(分层与分层),但程序按原样运行,无一例外。另外,我知道文档显示了诸如 stratified=StratifiedIfPossible 之类的内容,但出于某种原因,只有布尔值对我有用。
我没看到你在哪里调整 30:1 偏差。 If by stratification: no, stratification means the opposite (in some sense) of what you want: stratified sample is a sample 其中 class 分布与 "population" 中的分布大致相同。因此,通过 stratified=True
,您告诉 Orange 确保它保持 30:1 偏差。如果不分层,样本分布可能会随机偏离一点。
您可能想按照这些思路做一些事情:
# First, split the table into two tables with rows from different classes:
filt = Orange.data.filter.SameValue()
filt.position = -1
filt.value = 0
class0 = filt(mydata)
filt.value = 1
class1 = filt(mydata)
# Now class0 and class1 contain the rows from class 0 and 1, respectively
# Take 100 rows from each table:
sampler = Orange.data.sample.SubsetIndices2(p0=100)
ind = sampler(class0)
samp0 = class0.select(ind, 0)
ind = sampler(class1)
samp1 = class1.select(ind, 0)
# samp0 and samp1 now contain 100 rows from each class
# We have to merge them into a single table
balanced_data = Orange.data.Table(samp0)
balanced_data.extend(samp1)
在此之后,balanced_data
将有 1:1 class 比率。
这现在可能正是您想要的,不过:这个 classifier 会过分偏爱少数 class,因此它的性能会非常糟糕。根据我的经验,您想降低 30:1 比率,但不要降低太多。
正在寻求 Orange 专家的帮助。
我有一个大约 600 万行的数据集。为了简单起见,我们将只考虑两列。一个是正十进制数,作为连续值导入。另一个是离散值(0 或 1),其中 1 与 0 的比率为 30:1。
我正在使用分类树(我将其标记为 'learner')来获取分类器。然后我尝试对我的数据集进行交叉验证,同时针对压倒性的 30:1 样本偏差进行调整。我已经尝试了几种变体来执行此操作,但无论我是否对数据进行分层,都会继续得到相同的结果。
下面是我的代码,我已经注释掉了我尝试过的各行代码(同时使用 True 和 False 值进行分层):
import Orange
import os
import time
import operator
start = time.time()
print "Starting"
print ""
mydata = Orange.data.Table("testData.csv")
# This is used only for the test_with_indices method below
indicesCV = Orange.data.sample.SubsetIndicesCV(mydata)
# I only want the highest level classifier so max_depth=1
learner = Orange.classification.tree.TreeLearner(max_depth=1)
# These are the lines I've tried:
#res = Orange.evaluation.testing.cross_validation([learner], mydata, folds=5, stratified=True)
#res = Orange.evaluation.testing.proportion_test([learner], mydata, 0.8, 100, store_classifiers=1)
res = Orange.evaluation.testing.proportion_test([learner], mydata, learning_proportion=0.8, times=10, stratification=True, store_classifiers=1)
#res = Orange.evaluation.testing.test_with_indices([learner], mydata, indicesCV)
f = open('results.txt', 'a')
divString = "\n##### RESULTS (" + time.strftime("%Y-%m-%d %H:%M:%S") + ") #####"
f.write(divString)
f.write("\nAccuracy: %.2f" % Orange.evaluation.scoring.CA(res)[0])
f.write("\nPrecision: %.2f" % Orange.evaluation.scoring.Precision(res)[0])
f.write("\nRecall: %.2f" % Orange.evaluation.scoring.Recall(res)[0])
f.write("\nF1: %.2f\n" % Orange.evaluation.scoring.F1(res)[0])
tree = learner(mydata)
f.write(tree.to_string(leaf_str="%V (%M out of %N)"))
print tree.to_string(leaf_str="%V (%M out of %N)")
end = time.time()
print "Ending"
timeStr = "Execution time: " + str((end - start) / 60) + " minutes"
f.write(timeStr)
f.close()
注意:可能看起来有语法错误(分层与分层),但程序按原样运行,无一例外。另外,我知道文档显示了诸如 stratified=StratifiedIfPossible 之类的内容,但出于某种原因,只有布尔值对我有用。
我没看到你在哪里调整 30:1 偏差。 If by stratification: no, stratification means the opposite (in some sense) of what you want: stratified sample is a sample 其中 class 分布与 "population" 中的分布大致相同。因此,通过 stratified=True
,您告诉 Orange 确保它保持 30:1 偏差。如果不分层,样本分布可能会随机偏离一点。
您可能想按照这些思路做一些事情:
# First, split the table into two tables with rows from different classes:
filt = Orange.data.filter.SameValue()
filt.position = -1
filt.value = 0
class0 = filt(mydata)
filt.value = 1
class1 = filt(mydata)
# Now class0 and class1 contain the rows from class 0 and 1, respectively
# Take 100 rows from each table:
sampler = Orange.data.sample.SubsetIndices2(p0=100)
ind = sampler(class0)
samp0 = class0.select(ind, 0)
ind = sampler(class1)
samp1 = class1.select(ind, 0)
# samp0 and samp1 now contain 100 rows from each class
# We have to merge them into a single table
balanced_data = Orange.data.Table(samp0)
balanced_data.extend(samp1)
在此之后,balanced_data
将有 1:1 class 比率。
这现在可能正是您想要的,不过:这个 classifier 会过分偏爱少数 class,因此它的性能会非常糟糕。根据我的经验,您想降低 30:1 比率,但不要降低太多。