Java - 批处理文本文件的方法比单独执行相同次数的相同操作要慢得多

标签 java text methods batch-processing text-classification

我编写了一个方法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/

相关文章:

c# - methods() 应该放在哪里?

java - Android检测应用程序何时暂停

html - 在跨度中换行到下一行的居中文本

java - 从文本文件读取数据,一个写得不好的文本文件

c++ - 在 C++ 中,如何将对象的方法作为参数传递给函数?

c# - CLR 中方法表的精确布局(4.0 版)

java - 将 JUnitCore 与 Spring 结合使用

java - mybatis使用动态sql foreach

Java - 是否可以使用方法签名输出堆栈跟踪?

regex - Powershell以字符串模式显示的5位数字格式