Вопрос по java, numpy – Как вызвать функцию Java из Python / Numpy?

7

Мне понятно, как расширить Python с помощью C ++, но что если я захочу написать функцию на Java для использования с numpy?

Вот простой сценарий: я хочу вычислить среднее значение для пустого массива, используя класс Java. Как я могу передать вектор NumPy в класс Java и собрать результат?

Спасибо за любую помощь!

это скорее стратегическое решение, у меня сейчас не так много Java-кода. Многие люди используют C ++ для научных вычислений, но у меня есть ощущение, что Java может заменить C ++ для этого в будущем. Так что в идеале python / numpy должен иметь возможность использовать классы C ++ и Java (например, matlab). Если сборка мусора действительно является проблемой, можно расширить Python с помощью C ++, иначе Java будет лучше Mannaggia
Я не видел какой-либо тенденции к широкому распространению Java в научном сообществе, и, учитывая, что, похоже, у вас нет большого количества кода для конвертации, лучше использовать проверенные инструменты, такие как Cython, а не работать в неизведанные и неподдерживаемые воды с Явой. Стратегическое решение более вероятно прагматично для использования технологий, доступных сегодня. JoshAdel
Ну, я не ищу клона, потому что у меня есть довольно много кода, и я считаю, что он очень хорош. Жаль, что нет прямого способа использовать numpy с Java ... Mannaggia
Является ли кодовая база Java достаточно значительной по размеру, чтобы вы не могли просто переписать чувствительные к производительности разделы в Cython и использовать numpy / python для остальных? JoshAdel

Ваш Ответ

3   ответа
13

ответом, так как чувствую, что по этой теме не так много информации опереполнение стек. Я также думаю, что Java станет более актуальной в научных вычислениях (например, см. Пакет WEKA для интеллектуального анализа данных) из-за улучшения производительности и других хороших функций разработки программного обеспечения Java.

В общем, оказывается, что используя правильные инструменты, гораздо проще расширить Python с помощью Java, чем с C / C ++!

Обзор и оценка инструментов для вызова Java из Python

http: //pypi.python.org/pypi/JC: из-за отсутствия надлежащей документации этот инструмент бесполезен.

Py4J: требуется запустить процесс Java перед использованием Python. Как отмечали другие, это возможная точка отказа. Более того, не так много примеров использования задокументировано.

JPype: хотя разработка кажется смертью, она работает хорошо, и в Интернете есть много примеров (например, см.http: //kogs-www.informatik.uni-hamburg.de/~meine/weka-python для использования библиотек интеллектуального анализа данных, написанных на Java). Следовательно Я решил сосредоточиться на этом инструменте.

Установка JPype в Fedora 16

Я использую Fedora 16, поскольку при установке JPype в Linux возникают некоторые проблемы, я опишу свой подход. Скачать JPype, затем измените Setup.py скрипт, предоставляя путь JDK, в строке 48:

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

затем беги:

sudo python setup.py install

После успешной установки проверьте этот файл:

/ USR / lib64 / python2.7 / сайт-пакеты / 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):

/ USR / Библиотека / JVM / Java-1.5.0-GCJ-1.5.0.0 / JRE / Библиотека / x86_64 / клиент / libjvm.so / USR / Библиотека / JVM / Java-1.5.0-GCJ-1.5.0.0 / JRE / Библиотека / x86_64 / сервер / libjvm.so / USR / Библиотека / JVM / Java-1.6.0-OpenJDK-1.6.0.0.x86_64 / JRE / Библиотека / amd64 / сервер / libjvm.so

Наконец, добавьте следующую строку в ~ / .Bashrc (или запускайте его каждый раз перед открытием интерпретатора Python):

export JAVA_HOME='/usr/java/default'

(Приведенный выше каталог на самом деле является просто символической ссылкой на мою последнюю версию JDK, которая находится по адресу / USR / Java / jdk1.7.0_04).

Обратите внимание, что все тесты в каталоге, куда был загружен JPype, т. JPype-0.5.4.2 / тест / 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() 
Вызов Java-классов из Java также с использованием Numpy

Давайте начнем реализовывать 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);
}
}

Название класса немного вводит в заблуждение, так как мы не только нацелены на вычисление среднего числа векторов с нулевыми значениями (используя метод Compute_average), но также умножаем числовой вектор на скаляр (метод Умножить) и, наконец, умножение матриц (метод 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() 
2

что Jython - это один из лучших вариантов, который позволяет без проблем использовать объекты Java в Python. Я фактически интегрировал weka с моими программами на python, и это было очень легко. Просто импортируйте классы weka и вызывайте их, как в java-код

http: //www.jython.org

Да, я знаю. Но проблема с Jython заключается в том, что, к сожалению, он не поддерживает Numpy, а также многие другие библиотеки Python для научных вычислений. Mannaggia
1
Кроме того, документация JCC ужасна (или я должен сказать, что ее нет?), я не понял, как ее использовать ... Mannaggia
это может быть полезно, но я надеялся на некоторые пошаговые инструкции с использованием какой-нибудь обертки более высокого уровня. Теоретически следует: 1) вызвать Java из C ++, а затем 2) вызвать C ++ из Python. Mannaggia

Похожие вопросы