代码之家  ›  专栏  ›  技术社区  ›  Sufian Latif

通过java运行时使用pickled python类

  •  1
  • Sufian Latif  · 技术社区  · 6 年前

    我使用scikit learn从一些字符串构建了一个二进制SVM分类器:

    count_vect = TfidfVectorizer(sublinear_tf=True, min_df=10, norm='l2', encoding='latin-1', ngram_range=(1, 4))
    X_counts = count_vect.fit_transform(X)
    tfidf_transformer = TfidfTransformer()
    X_tfidf = tfidf_transformer.fit_transform(X_counts)
    clf = SGDClassifier(loss='hinge', penalty='l2', tol=1e-3)
    clf.fit(X_tfidf, Y)
    

    然后,我围绕经过训练的分类器创建了一个包装类并对其进行了pickle:

    class Classifier:
        def __init__(self, clf, vect):
            self.classifier = clf
            self.vectorizer = vect
    
        def classify(self, s):
            return self.classifier.predict(self.vectorizer.transform([s]))[0]
    
    with open('my_classifier.pkl', 'wb') as fout:
        pickle.dump(Classifier(clf, count_vect), fout)
    

    with open('my_classifier.pkl', 'rb') as fin:
        clf = pickle.load(fin)
    
    result = clf.classify(sys.argv[1])
    print(result)
    

    但是,当我试图通过java运行时执行脚本时,它显示了不正确的输出。

    public boolean classify(String s) throws IOException {
            String cmd = "python3 pkl_classifier.py \"" + s + "\"";
            Process p = Runtime.getRuntime().exec(cmd);
            BufferedReader stdIn = new BufferedReader(new InputStreamReader(p.getInputStream()));
    
            String out = stdIn.readLine();
            if (out != null) {
                switch (Integer.parseInt(out)) {
                    case 0: return false;
                    case 1: return true;
                    default: throw new RuntimeException("Error with classifier script:" + out);
                }
            }
    
            return false;
        }
    

    分类器的输出可以是0或1。但是这个java代码总是产生一个0。我已经把整个命令打印出来了( cmd )直接在终端执行,产生正确的输出。但是java运行时生成的输出总是0。

    1 回复  |  直到 6 年前
        1
  •  0
  •   Sufian Latif    6 年前

    刚发现问题。

    假设我要分类的字符串是 "lorem ipsum dolor sit amet"

    String cmd = "python3 pkl_classifier.py \"" + s + "\"";

    它看起来像

    python3 pkl_classifier.py "lorem ipsum dolor sit amet"

    这正是我想要执行的命令。当我打印出变量 cmd ,看起来还行。但是当我在python脚本中使用

    print(sys.argv)

    它看起来像

    ['pkl_classifier.py', '"lorem', 'ipsum', 'dolor', 'sit', 'amet"']

    然后我把剧本改成

    result = clf.classify(sys.argv[1])

    result = clf.classify(' '.join(sys.argv[1:]))

    效果很好!

    与其调整python脚本,不如使用另一个 exec() 方法 Process 类,该类将参数作为字符串数组。它将在内部处理参数中的空白。

    String[] cmd = { "python3", "pkl_classifier.py", s };
    p = Runtime.getRuntime().exec(cmd);