pasé algún tiempo en mi propia pregunta y me gustaría compartir mi respuesta ya que siento que no hay mucha información sobre este tema en stackoverflow. También creo que Java será más relevante en informática científica (por ejemplo, consulte el paquete WEKA para minería de datos) debido a la mejora del rendimiento y otras buenas características de desarrollo de software de Java.
En general, resulta que el uso de las herramientas adecuadas es mucho más fácil de extender con Java Python que con C/C++!
Descripción y evaluación de las herramientas para llamar a Java desde Python
http://pypi.python.org/pypi/JCC: por falta de documentación apropiada esta herramienta no sirve para nada.
Py4J: requiere iniciar el proceso de Java antes de usar python. Como señalado por otros, este es un posible punto de falla. Además, no se documentan muchos ejemplos de uso.
JPype: si bien el desarrollo parece ser la muerte, funciona bien y hay muchos ejemplos en él en la web (por ejemplo, ver http://kogs-www.informatik.uni-hamburg.de/~meine/weka-python/ para el uso de las bibliotecas de minería de datos escritos en Java). Por lo tanto, decidí enfocar en esta herramienta.
JPype la instalación en Fedora 16
estoy usando Fedora 16, ya que hay algunos problemas al instalar JPype en Linux, describo mi método. Descargar JPype, a continuación, modificar setup.py guión, proporcionando la ruta del JDK, en la línea 48:
self.javaHome = '/usr/java/default'
continuación, ejecute:
sudo python setup.py install
Afters instalación correcta, compruebe este archivo:
/usr/lib64/python2.7/site-packages/jpype/_linux.py
y eliminar o cambiar el nombre del método getDefaultJVMPath() en getDefaultJVMPath_old(), a continuación, añadir el siguiente método:
def getDefaultJVMPath():
return "/usr/java/default/jre/lib/amd64/server/libjvm.so"
enfoque alternativo: no hacer ningún cambio en el anterior archivo _linux.py, pero nunca use el método getDefaultJVMPath() (o métodos que llaman a este método). En el lugar donde se usa getDefaultJVMPath(), proporcione directamente la ruta a la JVM. Tenga en cuenta que hay varios caminos, por ejemplo en mi sistema también tengo las siguientes rutas, en referencia a las diferentes versiones de la JVM (no me queda claro si la JVM de cliente o servidor se adapta mejor):
- /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
Por último, agregue la siguiente línea al ~/.bashrc (o ejecutarlo cada vez que antes de abrir un intérprete de Python):
export JAVA_HOME='/usr/java/default'
(El directorio anterior es en realidad sólo un enlace simbólico a la última versión del JDK, que se encuentra en /usr/java/jdk1.7.0_04).
Tenga en cuenta que todas las pruebas en el directorio donde JPype ha sido descargado, es decir, JPype-0.5.4.2/test/testsuite.py fallará (así que no se preocupan por ellos).
Para ver si funciona, probar este script en 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()
llamadas clases Java de Java también utilizando Numpy
Vamos a empezar la implementación de una clase Java que contiene algunas funciones que quiero aplicar a matrices numpy. Como no existe un concepto de estado, utilizo funciones estáticas para no tener que crear ningún objeto Java (la creación de objetos Java no cambiaría nada).
/**
* 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);
}
}
El nombre de la clase es un poco engañoso, ya que no solo objetivo es calcular el promedio de un vector numpy (usando el método calcular_promedio), sino también multiplicar un vector numpy por un escalar (método multiplicar), y finalmente, la multiplicación de la matriz (método mult_mat).
Después de compilar la clase Java anterior que ahora puede ejecutar la siguiente secuencia de comandos de 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()
Tenga una mirada en [es-no-un-buen-numpy-clon-de-jython] (http://stackoverflow.com/q/316410/776084) – RanRag
así, no estoy Realmente estoy buscando un clon, ya que tengo bastante código numpy y me parece muy bueno. Es una pena que no haya una forma directa de usar numpy con Java ... – Mannaggia
¿La base de código Java es lo suficientemente significativa como para evitar que simplemente vuelva a escribir las secciones sensibles al rendimiento en Cython y use numpy/python para el ¿descanso? – JoshAdel