2015-01-14 105 views
5

C配列をPythonに渡す(numpy)には助けが必要です。 2倍のNumRows x NumInputsの2次元配列を持っていますが、それはPyArray_SimpleNewFromDataが正しく変換されないようです - デバッガはあまりポインタを表示しないので見えにくいです。2次元C配列をpythonに渡すnumpy

2次元配列を渡す正しい方法は何でしょうか?

int NumRows = X_test.size(); 
int NumInputs = X_test_row.size(); 

double **X_test2 = new double*[NumRows]; 
for(int i = 0; i < NumRows; ++i) 
{ 
    X_test2[i] = new double[NumInputs]; 
} 


for(int r = 0; r < NumRows; ++r) 
{ 
    for(int c = 0; c < NumInputs; ++c) 
    { 
     X_test2[r][c] = X_test[r][c]; 
    } 
} 




const char *ScriptFName = "100-ABN-PREDICT"; 
char *FunctionName=NULL; 

FunctionName="PredictGBC_DBG"; 

npy_intp Dims[2]; 
Dims[0]= NumRows; 
Dims[1] = NumInputs; 

PyObject *ArgsArray; 
PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *pArgs; 

int row, col, rows, cols, size, type; 

const double* outArray; 
double ArrayItem; 

//=================== 

Py_Initialize(); 

pName = PyBytes_FromString(ScriptFName); 

pModule = PyImport_ImportModule(ScriptFName); 

if (pModule != NULL) 
{ 
    import_array(); // Required for the C-API 

    ArgsArray = PyArray_SimpleNewFromData (2, Dims, NPY_DOUBLE, X_test2);//SOMETHING WRONG 

    pDict = PyModule_GetDict(pModule); 

    pArgs = PyTuple_New (1); 
    PyTuple_SetItem (pArgs, 0, ArgsArray); 

    pFunc = PyDict_GetItemString(pDict, FunctionName); 

    if (pFunc && PyCallable_Check(pFunc)) 
    { 

     pValue = PyObject_CallObject(pFunc, pArgs);//CRASHING HERE 

     if (pValue != NULL) 
     { 
      rows = PyArray_DIM(pValue, 0); 
      cols = PyArray_DIM(pValue, 1); 
      size = PyArray_SIZE(pValue); 
      type = PyArray_TYPE(pValue); 


      // get direct access to the array data 
      //PyObject* m_obj; 
      outArray = static_cast<const double*>(PyArray_DATA(pValue)); 


      for (row=0; row < rows; row++) 
      { 
       ArrayItem = outArray[row]; 
       y_pred.push_back(ArrayItem); 
      } 

     } 
     else 
     { 
      y_pred.push_back(EMPTY_VAL); 
     } 
    } 
    else 
    { 
     PyErr_Print(); 
    }//pFunc && PyCallable_Check(pFunc) 



}//(pModule!=NULL 
else 
{ 
    PyErr_SetString(PyExc_TypeError, "Cannot call function ?!"); 
    PyErr_Print(); 
} 




Py_DECREF(pValue); 
Py_DECREF(pFunc); 

Py_DECREF(ArgsArray); 
Py_DECREF(pModule); 
Py_DECREF(pName); 


Py_Finalize(); 
+1

最初に、私は 'new'を参照しています。したがって、あなたがCのようなものであっても、より良いタグは' C++ 'やって第二に、私は 'X_test2'は2次元配列ではなく、配列の配列であると主張します。各サブアレイは同じサイズ( 'NumInputs')であるが、必ずしもそうである必要はない。 – Evert

+2

numpyとCのインタフェースとして非常に多く認められている 'Cython'を使用しても構わない場合は、もっと簡単にすることができます。その場合、おそらくPython/numpyで配列を割り振り、それをCルーチンに渡して計算を行うほうが簡単です(お勧めします)。 Cython wikiにいくつかの[examples](https://github.com/cython/cython/wiki/tutorials-NumpyPointerToC)があります。 numpyの配列は2Dであるが、次に単一のポインタを渡してCコードの中で1D配列として使用することに注意してください。したがって、私の以前のコメント(一部)。 – Evert

+0

もう少し複雑です:C++の部分は他のソフトウェアで使用されているDLLです。データを取得し、その形式をnumpyに変更し、すべての計算が完了した場所(pyikit-learn)に渡します。 – klubow

答えて

5

データを連続したメモリブロックにコピーする必要があります。 2次元配列を表現するために、numpyは1次元配列へのポインタ配列を使いません。 Numpyは、配列が(デフォルトで)row major orderという連続したメモリブロックに格納されることを期待しています。

PyArray_SimpleNew(...)を使用して配列を作成すると、numpyによってメモリが割り当てられます。たとえば、std::memcpyまたはstd::copyをループ上のループで使用して、X_test2をこの配列にコピーする必要があります。

この変更、次のとおりです。このような何かに

ArgsArray = PyArray_SimpleNewFromData (2, Dims, NPY_DOUBLE, X_test2);//SOMETHING WRONG 

を:

// PyArray_SimpleNew allocates the memory needed for the array. 
ArgsArray = PyArray_SimpleNew(2, Dims, NPY_DOUBLE); 

// The pointer to the array data is accessed using PyArray_DATA() 
double *p = (double *) PyArray_DATA(ArgsArray); 

// Copy the data from the "array of arrays" to the contiguous numpy array. 
for (int k = 0; k < NumRows; ++k) { 
    memcpy(p, X_test2[k], sizeof(double) * NumInputs); 
    p += NumInputs; 
} 

(それはX_test2のように見えるX_testのコピーであるので、あなたは上記のコードへの変更する場合がありますX_testからnumpyの配列に直接コピーしてください)

+0

ありがとう、私はすぐに確認した - それは動作するように思われる(私は後で詳しく調べる)。ちなみに、なぜ呼び出すのか分かるかもしれません:cols = PyArray_DIM(pValue、1);列数ieを返しません。 array.shape [1]? numpy配列がdouble型の場合は8を返し、int32の場合は4を返します。 – klubow

+0

'pValue'とは何ですか? 'PyArray_DIM()'の最初の引数はnumpy配列を保持するpythonオブジェクトでなければなりません。 'ArgsArray'。 –

+0

これは、質問に添付されたコードで、pValue = PyObject_CallObject(pFunc、pArgs)です。これはPythonから返された数値の配列です – klubow