我编写了一个方法processTrainDirectory
,它应该导入并处理给定目录中的所有文本文件。单独处理每个文件大约需要相同的时间(90毫秒),但是当我使用批量导入给定目录的方法时,每个文件的时间逐渐增加(300个文件后从90毫秒增加到超过4000毫秒)。批量导入方法如下:
public void processTrainDirectory(String folderPath, Category category) {
File folder = new File(folderPath);
File[] listOfFiles = folder.listFiles();
if (listOfFiles != null) {
for (File file : listOfFiles) {
if (file.isFile()) {
processTrainText(file.getPath(), category);
}
}
}
else {
System.out.println(foo);
}
}
正如我所说,方法 processTrainText
是按目录中的每个文本文件调用的。在 processTrainDirectory
内部使用时,此方法需要的时间会逐渐增加。方法processTrainText
如下:
public void processTrainText(String path, Category category){
trainTextAmount++;
Map<String, Integer> text = prepareText(path);
update(text, category);
}
我在 200 个不同的文本手册上调用了 processTrainText
200 次,花费的时间是 200 * 90ms。但是,当我有一个包含 200 个文件的目录并使用 processTrainDirectory
时,需要 90-92-96-104....3897-3940-4002ms,这要长得多。
当我第二次调用processTrainText
时,问题仍然存在;它不会重置。您知道这是为什么吗?或者原因是什么,以及我该如何解决它?
非常感谢任何帮助!
编辑:有人问其他调用的方法做了什么,所以这里是我的类 BayesianClassifier
中使用的所有方法,为了澄清起见,所有其他方法都被删除,在下面你可以找到类 Category
:
public class BayesianClassifier {
private Map<String, Integer> vocabulary;
private List<Category> categories;
private int trainTextAmount;
private int testTextAmount;
private GUI gui;
public Map<String, Integer> prepareText(String path) {
String text = readText(path);
String normalizedText = normalizeText(text);
String[] tokenizedText = tokenizeText(normalizedText);
return countText(tokenizedText);
}
public String readText(String path) {
BufferedReader br;
String result = "";
try {
br = new BufferedReader(new FileReader(path));
StringBuilder sb = new StringBuilder();
String line = br.readLine();
while (line != null) {
sb.append(line);
sb.append("\n");
line = br.readLine();
}
result = sb.toString();
br.close();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
public Map<String, Integer> countText(String[] words){
Map<String, Integer> result = new HashMap<>();
for(int i=0; i < words.length; i++){
if (!result.containsKey(words[i])){
result.put(words[i], 1);
}
else {
result.put(words[i], result.get(words[i]) + 1);
}
}
return result;
}
public void processTrainText(String path, Category category){
trainTextAmount++;
Map<String, Integer> text = prepareText(path);
update(text, category);
}
public void update(Map<String, Integer> text, Category category) {
category.addText();
for (Map.Entry<String, Integer> entry : text.entrySet()){
if(!vocabulary.containsKey(entry.getKey())){
vocabulary.put(entry.getKey(), entry.getValue());
category.updateFrequency(entry);
category.updateProbability(entry);
category.updatePrior();
}
else {
vocabulary.put(entry.getKey(), vocabulary.get(entry.getKey()) + entry.getValue());
category.updateFrequency(entry);
category.updateProbability(entry);
category.updatePrior();
}
for(Category cat : categories){
if (!cat.equals(category)){
cat.addWord(entry.getKey());
cat.updatePrior();
}
}
}
}
public void processTrainDirectory(String folderPath, Category category) {
File folder = new File(folderPath);
File[] listOfFiles = folder.listFiles();
if (listOfFiles != null) {
for (File file : listOfFiles) {
if (file.isFile()) {
processTrainText(file.getPath(), category);
}
}
}
else {
System.out.println(foo);
}
}
这是我的 Category
类(为了澄清起见,删除了所有不需要的方法:
public class Category {
private String categoryName;
private double prior;
private Map<String, Integer> frequencies;
private Map<String, Double> probabilities;
private int textAmount;
private BayesianClassifier bc;
public Category(String categoryName, BayesianClassifier bc){
this.categoryName = categoryName;
this.bc = bc;
this.frequencies = new HashMap<>();
this.probabilities = new HashMap<>();
this.textAmount = 0;
this.prior = 0.00;
}
public void addWord(String word){
this.frequencies.put(word, 0);
this.probabilities.put(word, 0.0);
}
public void updateFrequency(Map.Entry<String, Integer> entry){
if(!this.frequencies.containsKey(entry.getKey())){
this.frequencies.put(entry.getKey(), entry.getValue());
}
else {
this.frequencies.put(entry.getKey(), this.frequencies.get(entry.getKey()) + entry.getValue());
}
}
public void updateProbability(Map.Entry<String, Integer> entry){
double chance = ((double) this.frequencies.get(entry.getKey()) + 1) / (sumFrequencies() + bc.getVocabulary().size());
this.probabilities.put(entry.getKey(), chance);
}
public Integer sumFrequencies(){
Integer sum = 0;
for (Integer integer : this.frequencies.values()) {
sum = sum + integer;
}
return sum;
}
}
最佳答案
看起来每个文件的时间呈线性增长,而总时间呈二次方增长。这意味着对于每个文件,您都在处理所有先前文件的数据。事实上,你是:
updateProbability
调用 sumFrequencies
,它贯穿整个频率
,并随每个文件而增长。这就是罪魁祸首。只需创建一个字段 int sumFrequencies
并在“updateFrequency”中更新它。
作为进一步的改进,请考虑使用 Guava Multiset ,它以更简单、更有效的方式进行计数(无自动装箱)。修复代码后,请考虑让它在 CR 上进行审查;它有很多小问题。
关于Java - 批处理文本文件的方法比单独执行相同次数的相同操作要慢得多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34514462/