我正在尝试使用Weka构建文本分类器,但其中distributionForInstance
类的概率在{1}}中为1.0
,在所有其他情况下为0.0
,因此{{1总是返回与预测相同的类。培训中的某些内容无法正常工作。
classifyInstance
@relation test1
@attribute tweetmsg String
@attribute classValues {politica,sport,musicatvcinema,infogeneriche,fattidelgiorno,statopersonale,checkin,conversazione}
@DATA
"Renzi Berlusconi Salvini Bersani",politica
"Allegri insulta la terna arbitrale",sport
"Bravo Garcia",sport
测试方法
public void trainClassifier(final String INPUT_FILENAME) throws Exception
{
getTrainingDataset(INPUT_FILENAME);
//trainingInstances consists of feature vector of every input
for(Instance currentInstance : inputDataset)
{
Instance currentFeatureVector = extractFeature(currentInstance);
currentFeatureVector.setDataset(trainingInstances);
trainingInstances.add(currentFeatureVector);
}
classifier = new NaiveBayes();
try {
//classifier training code
classifier.buildClassifier(trainingInstances);
//storing the trained classifier to a file for future use
weka.core.SerializationHelper.write("NaiveBayes.model",classifier);
} catch (Exception ex) {
System.out.println("Exception in training the classifier."+ex);
}
}
private Instance extractFeature(Instance inputInstance) throws Exception
{
String tweet = inputInstance.stringValue(0);
StringTokenizer defaultTokenizer = new StringTokenizer(tweet);
List<String> tokens=new ArrayList<String>();
while (defaultTokenizer.hasMoreTokens())
{
String t= defaultTokenizer.nextToken();
tokens.add(t);
}
Iterator<String> a = tokens.iterator();
while(a.hasNext())
{
String token=(String) a.next();
String word = token.replaceAll("#","");
if(featureWords.contains(word))
{
double cont=featureMap.get(featureWords.indexOf(word))+1;
featureMap.put(featureWords.indexOf(word),cont);
}
else{
featureWords.add(word);
featureMap.put(featureWords.indexOf(word), 1.0);
}
}
attributeList.clear();
for(String featureWord : featureWords)
{
attributeList.add(new Attribute(featureWord));
}
attributeList.add(new Attribute("Class", classValues));
int indices[] = new int[featureMap.size()+1];
double values[] = new double[featureMap.size()+1];
int i=0;
for(Map.Entry<Integer,Double> entry : featureMap.entrySet())
{
indices[i] = entry.getKey();
values[i] = entry.getValue();
i++;
}
indices[i] = featureWords.size();
values[i] = (double)classValues.indexOf(inputInstance.stringValue(1));
trainingInstances = createInstances("TRAINING_INSTANCES");
return new SparseInstance(1.0,values,indices,1000000);
}
private void getTrainingDataset(final String INPUT_FILENAME)
{
try{
ArffLoader trainingLoader = new ArffLoader();
trainingLoader.setSource(new File(INPUT_FILENAME));
inputDataset = trainingLoader.getDataSet();
}catch(IOException ex)
{
System.out.println("Exception in getTrainingDataset Method");
}
System.out.println("dataset "+inputDataset.numAttributes());
}
private Instances createInstances(final String INSTANCES_NAME)
{
//create an Instances object with initial capacity as zero
Instances instances = new Instances(INSTANCES_NAME,attributeList,0);
//sets the class index as the last attribute
instances.setClassIndex(instances.numAttributes()-1);
return instances;
}
public static void main(String[] args) throws Exception
{
Classificatore wekaTutorial = new Classificatore();
wekaTutorial.trainClassifier("training_set_prova_tent.arff");
wekaTutorial.testClassifier("testing.arff");
}
public Classificatore()
{
attributeList = new ArrayList<Attribute>();
initialize();
}
private void initialize()
{
featureWords= new ArrayList<String>();
featureMap = new TreeMap<>();
classValues= new ArrayList<String>();
classValues.add("politica");
classValues.add("sport");
classValues.add("musicatvcinema");
classValues.add("infogeneriche");
classValues.add("fattidelgiorno");
classValues.add("statopersonale");
classValues.add("checkin");
classValues.add("conversazione");
}
我想为短消息创建文本分类器,此代码基于本教程http://preciselyconcise.com/apis_and_installations/training_a_weka_classifier_in_java.php。问题是分类器为tests.arff中的几乎每个消息预测了错误的类,因为类的概率不正确。 training_set_prova_tent.arff每个类的消息数相同。 我正在使用的示例使用featureWords.dat并将1.0与单词关联(如果它存在于消息中)而我想创建自己的字典,其中包含training_set_prova_tent中的单词以及测试中出现的单词并关联到每个单词发生次数。
P.S 我知道这正是我可以用过滤器StringToWordVector做的,但是我还没有找到任何例子来说明如何将这个过滤器用于两个文件:一个用于训练集,另一个用于测试集。因此,调整我发现的代码似乎更容易。
非常感谢
答案 0 :(得分:1)
好像你在某些关键点改变了website you referenced的代码,但不是很好。我会尝试起草你想要做的事以及我发现的错误。
您(可能)想要在extractFeature
中做的是
你在这种方法中忽略的是
您永远不会重置featureMap
。这条线
Map<Integer,Double> featureMap = new TreeMap<>();
最初位于extractFeatures
的开头,但您将其移至initialize
。这意味着您总是将单词计数加起来,但从不重置它们。对于每条新推文,您的字数也包括以前所有推文的字数。我确信这不是你想要的。
您没有使用您想要的字词初始化featureWords
。是的,您创建了一个空列表,但是每个推文都会迭代填充它。原始代码在initialize
方法中初始化了一次,之后它从未改变过。这有两个问题:
class
属性始终位于其他位置。这两行适用于原始代码,因为featureWords.size()
基本上是常量,但在您的代码中,类标签将位于索引5,然后是8,然后是12,依此类推,但必须< / strong>每个实例都相同。indices[i] = featureWords.size(); values[i] = (double) classValues.indexOf(inputInstance.stringValue(1));
这也体现在您使用每条新推文构建新的attributeList
,而不是仅在initialize
中构建一次,这对于已经解释过的原因是不好的。
可能有更多的东西,但是 - 实际上 - 你的代码是相当无法修复的。您想要的更接近您修改的教程源代码而不是您的版本。
此外,您应该查看StringToWordVector,因为看起来这正是您想要做的事情:
将String属性转换为一组属性,表示字符串中包含的文本中出现的单词(取决于tokenizer)信息。单词集(属性)由第一批过滤(通常是训练数据)确定。