8

Python を C++ で拡張する方法は明らかですが、numpy で使用する関数を Java で記述したい場合はどうすればよいでしょうか?

これは簡単なシナリオです: Java クラスを使用して numpy 配列の平均を計算したいと考えています。numpy ベクトルを Java クラスに渡し、結果を収集するにはどうすればよいですか?

助けてくれてありがとう!

4

3 に答える 3

13

私は自分の質問に時間を費やしましたが、 stackoverflowに関するこのトピックに関する情報があまりないと感じたので、回答を共有したいと思います。また、パフォーマンスの向上や Java のその他の優れたソフトウェア開発機能により、Java は科学計算 (たとえば、データ マイニング用の WEKA パッケージを参照) でより関連性が高くなると思います。


一般に、適切なツールを使用すると、Python を Java で拡張する方が C/C++ で拡張するよりもはるかに簡単であることがわかります。


Python から Java を呼び出すツールの概要と評価

  • http://pypi.python.org/pypi/JCC : 適切なドキュメントがないため、このツールは役に立ちません。

  • Py4J: Python を使用する前に Java プロセスを開始する必要があります。他の人が指摘したように、これは失敗の可能性のあるポイントです。さらに、多くの使用例が文書化されていません。

  • JPype : 開発は死んだように見えますが、うまく機能し、Web 上に多くの例があります (たとえば、使用方法についてはhttp://kogs-www.informatik.uni-hamburg.de/~meine/weka-python/を参照してください)。 Java で記述されたデータ マイニング ライブラリ) 。したがって、このツールに注目することにしました

Fedora 16 に JPype をインストールする

LinuxにJPypeをインストールするときにいくつかの問題があるため、Fedora 16を使用しています。私のアプローチについて説明します。JPypeをダウンロードし、48 行目に JDK パスを指定してsetup.pyスクリプトを変更します。

self.javaHome = '/usr/java/default'

次に実行します:

sudo python setup.py install

インストールが正常に完了したら、次のファイルを確認します。

/usr/lib64/python2.7/site-packages/jpype/_linux.py

メソッドgetDefaultJVMPath()を削除するか名前を変更してgetDefaultJVMPath_old()にし、次のメソッドを追加します。

def getDefaultJVMPath():
    return "/usr/java/default/jre/lib/amd64/server/libjvm.so"

別のアプローチ: 上記のファイル_linux.pyを変更しないでください。ただし、メソッド getDefaultJVMPath() (またはこのメソッドを呼び出すメソッド) は使用しないでください。getDefaultJVMPath()を使用する場所で、JVM へのパスを直接指定します。いくつかのパスがあることに注意してください。たとえば、私のシステムには、さまざまなバージョンの JVM を参照する次のパスもあります (クライアント JVM とサーバー JVM のどちらが適しているかはわかりません)。

  • /usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre/lib/x86_64/client/libjvm.so
  • /usr/lib/jvm/java-1.5.0-gcj-1.5.0.0/jre/lib/x86_64/server/libjvm.so
  • /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/amd64/server/libjvm.so

最後に、次の行を~/.bashrcに追加します(または、Python インタープリターを開く前に毎回実行します)。

export JAVA_HOME='/usr/java/default'

(上記のディレクトリは、実際には/usr/java/jdk1.7.0_04にある最後のバージョンの JDK への単なるシンボリック リンクです)。

JPype がダウンロードされたディレクトリ、つまりJPype-0.5.4.2/test/testsuite.py内のすべてのテストは失敗することに注意してください (そのため気にしないでください)。

動作するかどうかを確認するには、このスクリプトを Python でテストします。

import jpype 
jvmPath = jpype.getDefaultJVMPath() 
jpype.startJVM(jvmPath)
# print a random text using a Java class
jpype.java.lang.System.out.println ('Berlusconi likes women') 
jpype.shutdownJVM() 

Numpy も使用して Java から Java クラスを呼び出す

numpy arraysに適用したいいくつかの関数を含む Java クラスの実装を始めましょう。状態の概念がないため、Java オブジェクトを作成する必要がないように静的関数を使用します (Java オブジェクトを作成しても何も変わりません)。

/**
 * Cookbook to pass numpy arrays to Java via Jpype
 * @author Mannaggia
 */

package test.java;

public class Average2 {

public static double compute_average(double[] the_array){
    // compute the average
    double result=0;
    int i;
    for (i=0;i<the_array.length;i++){
        result=result+the_array[i];
    }
    return result/the_array.length;
}
// multiplies array by a scalar
public static double[] multiply(double[] the_array, double factor) {

    int i;
    double[] the_result= new double[the_array.length];
    for (i=0;i<the_array.length;i++) {
        the_result[i]=the_array[i]*factor;
    }
    return the_result;
}

/**
 * Matrix multiplication. 
 */
public static double[][] mult_mat(double[][] mat1, double[][] mat2){
    // find sizes
    int n1=mat1.length;
    int n2=mat2.length;
    int m1=mat1[0].length;
    int m2=mat2[0].length;
    // check that we can multiply
    if (n2 !=m1) {
        //System.err.println("Error: The number of columns of the first argument must equal the number of rows of the second");
        //return null;
        throw new IllegalArgumentException("Error: The number of columns of the first argument must equal the number of rows of the second");
    }
    // if we can, then multiply
    double[][] the_results=new double[n1][m2];
    int i,j,k;
    for (i=0;i<n1;i++){
        for (j=0;j<m2;j++){
            // initialize
            the_results[i][j]=0;
            for (k=0;k<m1;k++) {
                the_results[i][j]=the_results[i][j]+mat1[i][k]*mat2[k][j];
            }
        }
    }
    return the_results;
}

/**
 * @param args
 */
public static void main(String[] args) {
    // test case
    double an_array[]={1.0, 2.0,3.0,4.0};
    double res=Average2.compute_average(an_array);
    System.out.println("Average is =" + res);
}
}

クラスの名前は少し誤解を招きます。numpy ベクトルの平均を計算すること (メソッドcompute_averageを使用) だけでなく、numpy ベクトルをスカラーで乗算すること (メソッドmultiply )、そして最後に行列乗算 (メソッドmult_mat )。

上記の Java クラスをコンパイルすると、次の Python スクリプトを実行できるようになります。

import numpy as np
import jpype

jvmPath = jpype.getDefaultJVMPath() 
# we to specify the classpath used by the JVM
classpath='/home/mannaggia/workspace/TestJava/bin'
jpype.startJVM(jvmPath,'-Djava.class.path=%s' % classpath)

# numpy array
the_array=np.array([1.1, 2.3, 4, 6,7])
# build a JArray, not that we need to specify the Java double type using the jpype.JDouble wrapper
the_jarray2=jpype.JArray(jpype.JDouble, the_array.ndim)(the_array.tolist())
Class_average2=testPkg.Average2 
res2=Class_average2.compute_average(the_jarray2)
np.abs(np.average(the_array)-res2) # ok perfect match! 

# now try to multiply an array
res3=Class_average2.multiply(the_jarray2,jpype.JDouble(3))
# convert to numpy array
res4=np.array(res3) #ok

# matrix multiplication
the_mat1=np.array([[1,2,3], [4,5,6], [7,8,9]],dtype=float)
#the_mat2=np.array([[1,0,0], [0,1,0], [0,0,1]],dtype=float)
the_mat2=np.array([[1], [1], [1]],dtype=float)
the_mat3=np.array([[1, 2, 3]],dtype=float)

the_jmat1=jpype.JArray(jpype.JDouble, the_mat1.ndim)(the_mat1.tolist())
the_jmat2=jpype.JArray(jpype.JDouble, the_mat2.ndim)(the_mat2.tolist())
res5=Class_average2.mult_mat(the_jmat1,the_jmat2)
res6=np.array(res5) #ok

# other test
the_jmat3=jpype.JArray(jpype.JDouble, the_mat3.ndim)(the_mat3.tolist())
res7=Class_average2.mult_mat(the_jmat3,the_jmat2)
res8=np.array(res7)
res9=Class_average2.mult_mat(the_jmat2,the_jmat3)
res10=np.array(res9)

# test error due to invalid matrix multiplication
the_mat4=np.array([[1], [2]],dtype=float)
the_jmat4=jpype.JArray(jpype.JDouble, the_mat4.ndim)(the_mat4.tolist())
res11=Class_average2.mult_mat(the_jmat1,the_jmat4)

jpype.java.lang.System.out.println ('Goodbye!') 
jpype.shutdownJVM() 
于 2012-06-03T18:27:45.090 に答える
2

私は、Jython が最良のオプションの 1 つであると考えています。これにより、Python で Java オブジェクトをシームレスに使用できるようになります。実際に weka を Python プログラムに統合しましたが、とても簡単でした。weka クラスをインポートして、Python コード内で Java と同じように呼び出すだけです。

http://www.jython.org/

于 2012-09-13T20:01:59.703 に答える
1

numpy のサポートについてはよくわかりませんが、以下が役立つかもしれません。

http://pypi.python.org/pypi/JCC/

于 2012-05-22T18:24:44.910 に答える