具有真实价值特征的斯坦福分类器
Stanford Classifier with Real Valued Features
我想使用 Stanford Classifier 进行文本 class化。我的特征主要是文本特征,但也有一些数字特征(例如句子的长度)。
我从 ClassifierExample 开始,用一个简单的实值特征 F
替换当前特征,如果停车灯是 BROKEN
并且 100
=14=] 否则,将产生以下代码(除了第 10-16 行中的 makeStopLights()
函数,这只是原始 ClassifierExample class 的代码):
public class ClassifierExample {
protected static final String GREEN = "green";
protected static final String RED = "red";
protected static final String WORKING = "working";
protected static final String BROKEN = "broken";
private ClassifierExample() {} // not instantiable
// the definition of this function was changed!!
protected static Datum<String,String> makeStopLights(String ns, String ew) {
String label = (ns.equals(ew) ? BROKEN : WORKING);
Counter<String> counter = new ClassicCounter<>();
counter.setCount("F", (label.equals(BROKEN)) ? 100 : 0.1);
return new RVFDatum<>(counter, label);
}
public static void main(String[] args) {
// Create a training set
List<Datum<String,String>> trainingData = new ArrayList<>();
trainingData.add(makeStopLights(GREEN, RED));
trainingData.add(makeStopLights(GREEN, RED));
trainingData.add(makeStopLights(GREEN, RED));
trainingData.add(makeStopLights(RED, GREEN));
trainingData.add(makeStopLights(RED, GREEN));
trainingData.add(makeStopLights(RED, GREEN));
trainingData.add(makeStopLights(RED, RED));
// Create a test set
Datum<String,String> workingLights = makeStopLights(GREEN, RED);
Datum<String,String> brokenLights = makeStopLights(RED, RED);
// Build a classifier factory
LinearClassifierFactory<String,String> factory = new LinearClassifierFactory<>();
factory.useConjugateGradientAscent();
// Turn on per-iteration convergence updates
factory.setVerbose(true);
//Small amount of smoothing
factory.setSigma(10.0);
// Build a classifier
LinearClassifier<String,String> classifier = factory.trainClassifier(trainingData);
// Check out the learned weights
classifier.dump();
// Test the classifier
System.out.println("Working instance got: " + classifier.classOf(workingLights));
classifier.justificationOf(workingLights);
System.out.println("Broken instance got: " + classifier.classOf(brokenLights));
classifier.justificationOf(brokenLights);
}
}
根据我对线性 classifier 的理解,特征 F
应该可以使 classification 任务变得相当简单——毕竟,我们只需要检查 F
大于某个阈值。但是,classifier returns WORKING
在测试集中的每个实例上。
现在我的问题是:我是不是做错了什么,我是否还需要更改代码的其他部分才能使实值特征起作用,或者我对线性的理解有问题class制造商?
您的代码看起来不错。请注意,通常使用最大熵分类器可以提供二进制值特征(1 或 0)。
这里是关于最大熵分类器的更多阅读:http://web.stanford.edu/class/cs124/lec/Maximum_Entropy_Classifiers
查看标题为:"Feature-Based Linear Classifiers" 的幻灯片,了解最大熵分类器的具体概率计算。
这是您的示例案例的公式,其中包含 1 个特征和 2 个 类("works"、"broken"):
probability(c1) = exp(w1 * f1) / total
probability(c2) = exp(w2 * f1) / total
total = exp(w1 * f1) + exp(w2 * f1)
w1 是 "works" 的学习权重,w2 是 "broken"
的学习权重
分类器选择较高的概率。请注意,f1 = (100 或 0.1) 您的特征值。
如果你考虑你的具体示例数据,因为你有(2 类,1 个特征,特征总是正的),不可能建立一个最大熵分类器来分离数据,它总是会以一种或另一种方式猜测。
为了争论起见,说w1 > w2
。
说 v > 0
是你的特征值(100 或 0.1)。
然后 w1 * v > w2 * v
,因此 exp(w1 * v) > exp(w2 * v)
,因此无论 v 的值是多少,您总是会为 class1 分配更多概率。
我想使用 Stanford Classifier 进行文本 class化。我的特征主要是文本特征,但也有一些数字特征(例如句子的长度)。
我从 ClassifierExample 开始,用一个简单的实值特征 F
替换当前特征,如果停车灯是 BROKEN
并且 100
=14=] 否则,将产生以下代码(除了第 10-16 行中的 makeStopLights()
函数,这只是原始 ClassifierExample class 的代码):
public class ClassifierExample {
protected static final String GREEN = "green";
protected static final String RED = "red";
protected static final String WORKING = "working";
protected static final String BROKEN = "broken";
private ClassifierExample() {} // not instantiable
// the definition of this function was changed!!
protected static Datum<String,String> makeStopLights(String ns, String ew) {
String label = (ns.equals(ew) ? BROKEN : WORKING);
Counter<String> counter = new ClassicCounter<>();
counter.setCount("F", (label.equals(BROKEN)) ? 100 : 0.1);
return new RVFDatum<>(counter, label);
}
public static void main(String[] args) {
// Create a training set
List<Datum<String,String>> trainingData = new ArrayList<>();
trainingData.add(makeStopLights(GREEN, RED));
trainingData.add(makeStopLights(GREEN, RED));
trainingData.add(makeStopLights(GREEN, RED));
trainingData.add(makeStopLights(RED, GREEN));
trainingData.add(makeStopLights(RED, GREEN));
trainingData.add(makeStopLights(RED, GREEN));
trainingData.add(makeStopLights(RED, RED));
// Create a test set
Datum<String,String> workingLights = makeStopLights(GREEN, RED);
Datum<String,String> brokenLights = makeStopLights(RED, RED);
// Build a classifier factory
LinearClassifierFactory<String,String> factory = new LinearClassifierFactory<>();
factory.useConjugateGradientAscent();
// Turn on per-iteration convergence updates
factory.setVerbose(true);
//Small amount of smoothing
factory.setSigma(10.0);
// Build a classifier
LinearClassifier<String,String> classifier = factory.trainClassifier(trainingData);
// Check out the learned weights
classifier.dump();
// Test the classifier
System.out.println("Working instance got: " + classifier.classOf(workingLights));
classifier.justificationOf(workingLights);
System.out.println("Broken instance got: " + classifier.classOf(brokenLights));
classifier.justificationOf(brokenLights);
}
}
根据我对线性 classifier 的理解,特征 F
应该可以使 classification 任务变得相当简单——毕竟,我们只需要检查 F
大于某个阈值。但是,classifier returns WORKING
在测试集中的每个实例上。
现在我的问题是:我是不是做错了什么,我是否还需要更改代码的其他部分才能使实值特征起作用,或者我对线性的理解有问题class制造商?
您的代码看起来不错。请注意,通常使用最大熵分类器可以提供二进制值特征(1 或 0)。
这里是关于最大熵分类器的更多阅读:http://web.stanford.edu/class/cs124/lec/Maximum_Entropy_Classifiers
查看标题为:"Feature-Based Linear Classifiers" 的幻灯片,了解最大熵分类器的具体概率计算。
这是您的示例案例的公式,其中包含 1 个特征和 2 个 类("works"、"broken"):
probability(c1) = exp(w1 * f1) / total
probability(c2) = exp(w2 * f1) / total
total = exp(w1 * f1) + exp(w2 * f1)
w1 是 "works" 的学习权重,w2 是 "broken"
的学习权重分类器选择较高的概率。请注意,f1 = (100 或 0.1) 您的特征值。
如果你考虑你的具体示例数据,因为你有(2 类,1 个特征,特征总是正的),不可能建立一个最大熵分类器来分离数据,它总是会以一种或另一种方式猜测。
为了争论起见,说w1 > w2
。
说 v > 0
是你的特征值(100 或 0.1)。
然后 w1 * v > w2 * v
,因此 exp(w1 * v) > exp(w2 * v)
,因此无论 v 的值是多少,您总是会为 class1 分配更多概率。