Я занимаюсь разработкой научного приложения, в значительной степени опирающегося на манипулирование массивами в Java с использованием ND4j (в настоящее время версия 1.0.0-бета5). На протяжении всего моего конвейера мне необходимо динамически выбирать несмежное подмножество матрицы [2,195102] (точнее, несколько десятков / сотен столбцов). Любая идея, как добиться этого в этих рамках?
Короче говоря, я пытаюсь выполнить эту операцию Python / Numpy:
import numpy as np
arrayData = np.array([[1, 5, 0, 6, 2, 0, 9, 0, 5, 2],
[3, 6, 1, 0, 4, 3, 1, 4, 8, 1]])
arrayIndex = np.array((1,5,6))
res = arrayData[:, arrayIndex]
# res value is
# array([[5, 0, 9],
# [6, 3, 1]])
До сих пор мне удалось выбрать нужный столбец с помощьюфункция NDArray.getColumns (вместе с NDArray.data (). asInt () из indexArray для предоставления значений индекса). Проблема заключается в том, что в документации явно говорится о получении информации во время вычислений: «Обратите внимание, что ЭТО НЕ ДОЛЖНО ИСПОЛЬЗОВАТЬСЯ ДЛЯ СКОРОСТИ» (см. Документацию NDArray.ToIntMatrix () , чтобы увидеть полное сообщение- другой метод, та же операция).
Я посмотрел на различные прототипы для NDArray.get () , и ни один из них, похоже, не отвечает требованиям. Я полагаю, что NDArray.getWhere () может работать - если он, как я предполагаю, возвращает только элементы, которые удовлетворяют условию - но до сих пор не смогли его использовать. Документация относительно проста, когда речь идет об объяснении необходимых аргументов / использования.
Спасибо всем за потраченное время и помощь:)
РЕДАКТИРОВАТЬ (04/11/2019): некоторая точность относительночто я пробовалЯ поигрался с NDArray.get () и использовал индексы:
INDArray arrayData = Nd4j.create(new int[]
{1, 5, 0, 6, 2, 0, 9, 0, 5, 2,
3, 6, 1, 0, 4, 3, 1, 4, 8, 1}, new long[]{2, 10}, DataType.INT);
INDArray arrayIndex = Nd4j.create(new int[]{1, 5, 6}, new long[]{1, 3}, DataType.INT);
INDArray colSelection = null;
//index free version
colSelection = arrayData.getColumns(arrayIndex.toIntVector());
/*
* colSelection value is
* [[5, 0, 9],
* [6, 3, 1]]
* but the toIntVector() call pulls the data from the back-end storage
* and re-inject them. That is presumed to be slow.
* - 2 columns selected (arrayIndex = {1, 5}), ==> 4001 ms for 100000 iterations
* - 3 columns selected (arrayIndex = {1, 5, 6}), ==> 5339 ms for 100000 iterations
* - 4 columns selected (arrayIndex = {1, 5, 6 ,2}), ==> 7016 ms for 100000 iterations
*/
//index version
colSelection = arrayData.get(NDArrayIndex.all(), NDArrayIndex.indices(arrayIndex.toLongVector()));
/*
* Same result, but same problem regarding toLongVector() this time around.
* - 2 columns selected (arrayIndex = {1, 5}), ==> 3200 ms for 100000 iterations
* - 3 columns selected (arrayIndex = {1, 5, 6}), ==> 4269 ms for 100000 iterations
* - 4 columns selected (arrayIndex = {1, 5, 6 ,2}), ==> 5252 ms for 100000 iterations
*/
//weird but functional version (that I just discovered)
colSelection = arrayData.transpose().get(arrayIndex); // the transpose operation is necessary to not hit an IllegalArgumentException: Illegal slice 5
// note that transposing the arrayIndex leads to an IllegalArgumentException: Illegal slice 6 (as it is trying to select the element at the line idx 1, column 5, depth 6, which does not exist)
/*
* colSelection value is
* [5, 6, 0, 3, 9, 1]
* The array is flattened... calling a reshape(arrayData.shape()[0],arrayIndex.shape()[1]) yields
* [[5, 6, 0],
* [3, 9, 1]]
* which is wrong.
*/
colSelection = colSelection.reshape(arrayIndex.shape()[1],arrayData.shape()[0]).transpose();
/* yields the right result
* [[5, 0, 9],
* [6, 3, 1]]
* While this seems to be the correct way to handle the memory the performance are low:
* - 2 columns selected (arrayIndex = {1, 5}), ==> 8225 ms for 100000 iterations
* - 3 columns selected (arrayIndex = {1, 5, 6}), ==> 8980 ms for 100000 iterations
* - 4 columns selected (arrayIndex = {1, 5, 6 ,2}), ==> 9453 ms for 100000 iterations
Plus, this is very roundabout method for such a "simple" operation
* if the repacking of the data is commented out, the timing become:
* - 2 columns selected (arrayIndex = {1, 5}), ==> 6987 ms for 100000 iterations
* - 3 columns selected (arrayIndex = {1, 5, 6}), ==> 7976 ms for 100000 iterations
* - 4 columns selected (arrayIndex = {1, 5, 6 ,2}), ==> 8336 ms for 100000 iterations
*/
С этими скоростями все в порядке, даже не зная, на какой машине я работаю, но эквивалентный код Python дает:
- 2 выбранных столбца (arrayIndex = {1, 5}), ==> 171 мс на 100000 итераций
- 3 выбранных столбца (arrayIndex = {1, 5, 6}), ==> 173мс на 100000 итераций
- 4 выбранных столбца (arrayIndex = {1, 5, 6, 2}), ==> 173 мс на 100000 итераций
Эти реализации java в лучшем случаеВ 20 раз медленнее, чем у питона.