我花了一些时间回答自己的问题,并希望分享我的答案,因为我觉得关于 stackoverflow的
这个主题的信息不多。我还认为,由于Java的性能和其他良好的软件开发功能的改进,Java将在科学计算中变得更加重要(例如,请参见WEKA软件包进行数据挖掘)。
总的来说,事实证明,使用正确的工具,用Java扩展Python比使用C / C ++容易得多!
概述和评估从Python调用Java的工具
http://pypi.python.org/pypi/JCC:由于没有适当的文档,此工具无用。
Py4J:需要在使用python之前启动Java进程。正如其他人所说,这可能是失败的地方。而且,没有记录使用的很多例子。
JPype:虽然发展似乎是死亡,它运作良好,并有在网络上就可以了许多实例(例如,见http://kogs-www.informatik.uni-hamburg.de/~meine/weka-python/使用用Java编写的数据挖掘库)。因此, 我决定专注于此工具 。
在Fedora 16上安装JPype
我正在使用Fedora
16,因为在Linux上安装JPype时会遇到一些问题,因此我将介绍我的方法。下载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'
(上面的目录实际上只是到我的最新JDK版本的符号链接,该版本位于 /usr/java/jdk1.7.0_04 )。
请注意,已下载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 classjpype.java.lang.System.out.println ('Berlusconi likes women') jpype.shutdownJVM()也使用Numpy从Java调用Java类
让我们开始实现一个Java类,其中包含一些我想应用于 numpy arrays的
函数。由于没有状态的概念,因此我使用静态函数,因此不需要创建任何Java对象(创建Java对象不会改变任何内容)。
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 scalarpublic 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;}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;}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向量与标量 相乘
(方法 乘法 ),最后将矩阵相乘乘法(方法 mult_mat )。
编译完上述Java类之后,我们现在可以运行以下Python脚本:
import numpy as npimport jpypejvmPath = jpype.getDefaultJVMPath() # we to specify the classpath used by the JVMclasspath='/home/mannaggia/workspace/TestJava/bin'jpype.startJVM(jvmPath,'-Djava.class.path=%s' % classpath)# numpy arraythe_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 wrapperthe_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 arrayres3=Class_average2.multiply(the_jarray2,jpype.JDouble(3))# convert to numpy arrayres4=np.array(res3) #ok# matrix multiplicationthe_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 testthe_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 multiplicationthe_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()


