tôi đã dành một số thời gian trên câu hỏi của riêng tôi và muốn chia sẻ câu trả lời của tôi như là tôi cảm thấy không có nhiều thông tin về chủ đề này trên stackoverflow. Tôi cũng nghĩ Java sẽ trở nên có liên quan hơn trong tính toán khoa học (ví dụ: xem gói WEKA để khai thác dữ liệu) vì cải thiện hiệu suất và các tính năng phát triển phần mềm tốt khác của Java.
Nói chung, nó quay ra rằng việc sử dụng các công cụ thích hợp nó là dễ dàng hơn nhiều để mở rộng Python với Java so với C/C++!
Tổng quan và đánh giá các công cụ để gọi Java từ Python
http://pypi.python.org/pypi/JCC: vì không có tài liệu thích hợp công cụ này là vô ích.
Py4J: yêu cầu bắt đầu quá trình Java trước khi sử dụng python. Như nhận xét bởi những người khác, đây là một điểm có thể thất bại. Hơn nữa, không có nhiều ví dụ sử dụng được ghi lại.
JPype: mặc dù phát triển dường như là cái chết, nó hoạt động tốt và có nhiều ví dụ về nó trên web (ví dụ: xem http://kogs-www.informatik.uni-hamburg.de/~meine/weka-python/ cho việc sử dụng thư viện khai thác dữ liệu viết bằng Java). Do đó Tôi quyết định tập trung trên công cụ này.
JPype Cài đặt trên Fedora 16
Tôi đang sử dụng Fedora 16, vì có một số vấn đề khi cài đặt JPype trên Linux, tôi mô tả cách tiếp cận của tôi. Tải JPype, sau đó sửa đổi setup.py kịch bản bằng cách cung cấp các con đường JDK, phù hợp 48:
self.javaHome = '/usr/java/default'
sau đó chạy:
sudo python setup.py install
Afters cài đặt thành công, kiểm tra tập tin này:
/usr/lib64/python2.7/site-packages/jpype/_linux.py
và loại bỏ hoặc đổi tên các phương pháp getDefaultJVMPath() vào getDefaultJVMPath_old(), sau đó thêm các phương pháp sau đây:
def getDefaultJVMPath():
return "/usr/java/default/jre/lib/amd64/server/libjvm.so"
Alternative tiếp cận: không thực hiện bất kỳ thay đổi ở trên tệp _linux.py, nhưng không bao giờ sử dụng phương thức getDefaultJVMPath() (hoặc phương thức gọi phương thức này). Tại nơi sử dụng getDefaultJVMPath() cung cấp trực tiếp đường dẫn đến JVM. Lưu ý rằng có một số con đường, ví dụ như trong hệ thống của tôi, tôi cũng có các đường dẫn sau đây, đề cập đến các phiên bản khác nhau của JVM (nó không phải là rõ ràng với tôi cho dù khách hàng hoặc máy chủ JVM là phù hợp hơn):
- /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/máy chủ/libjvm.so
- /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/amd64/server/libjvm.so
Cuối cùng, thêm dòng sau vào ~/.bashrc (hoặc chạy nó mỗi lần trước khi mở một thông dịch viên python):
export JAVA_HOME='/usr/java/default'
(Thư mục trên là trong thực tế chỉ là một liên kết tượng trưng đến phiên bản cuối cùng của tôi về JDK, mà nằm ở /usr/java/jdk1.7.0_04).
Lưu ý rằng tất cả các thử nghiệm trong thư mục mà JPype đã được tải xuống, tức là JPype-0.5.4.2/test/testsuite.py sẽ không thành công (do đó, không quan tâm đến chúng).
Để xem nếu nó hoạt động, kiểm tra kịch bản này trong 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()
Calling lớp Java từ Java cũng sử dụng NumPy
Hãy bắt đầu thực hiện một lớp Java có chứa một số chức năng mà tôi muốn áp dụng cho mảng numpy. Vì không có khái niệm trạng thái, tôi sử dụng các hàm tĩnh để không cần phải tạo bất kỳ đối tượng Java nào (việc tạo các đối tượng Java sẽ không thay đổi bất kỳ thứ gì).
/**
* 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);
}
}
Tên của lớp là một chút sai lầm, như chúng ta không chỉ nhằm mục đích tính toán trung bình của một vector NumPy (sử dụng phương pháp này compute_average), mà còn nhân lên một vector NumPy bởi một vô hướng (phương pháp nhân) và cuối cùng, nhân ma trận (phương pháp mult_mat).
Sau khi biên dịch lớp Java trên bây giờ chúng tôi có thể chạy các script Python sau:
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()
Có một cái nhìn tại [là-có-một-tốt-NumPy-clone-cho-Jython] (http://stackoverflow.com/q/316410/776084) – RanRag
tốt, tôi không thực sự tìm kiếm một bản sao, vì tôi có khá một số mã gumpy và tôi thấy gumpy rất tốt. Đó là một điều đáng tiếc không có cách trực tiếp để sử dụng gọn gàng với Java ... – Mannaggia
Cơ sở mã Java có đủ kích thước để ngăn cản bạn chỉ viết lại các phần nhạy cảm về hiệu suất trong Cython và sử dụng numpy/python cho nghỉ ngơi? – JoshAdel