2015-01-14 13 views
5

Ho bisogno di aiuto per passare l'array C a python (numpy). Ho 2d array di Doppi NumRows x NumInputs, sembra che PyArray_SimpleNewFromData non lo converta correttamente: è difficile da vedere perché il debugger non mostra molto, solo i puntatori.Passaggio di matrice C bidimensionale a python numpy

Quale sarebbe il modo giusto per passare un array bidimensionale?

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

In primo luogo, vedo 'new', quindi suppongo che il tag migliore sia' C++ ', anche se è in gran parte simile a C quello che sei facendo. In secondo luogo, direi che "X_test2" non è una matrice bidimensionale, ma piuttosto una matrice di matrici. Succede solo che ogni subarray ha la stessa dimensione ('NumInputs'), ma non deve essere. – Evert

+2

Se non ti dispiace usare 'Cython', che è uno standard molto accettato per interfacciare numpy e C, puoi renderlo molto più semplice. Anche se in questo caso, probabilmente è più semplice (consigliato?) Allocare l'array in Python/numpy, e quindi passarlo alla routine C per eseguire i calcoli (quindi il secondo ciclo for, suppongo). Ci sono alcuni [esempi] (https://github.com/cython/cython/wiki/tutorials-NumpyPointerToC) nella wiki Cython per aiutarti. Nota come quella matrice numpy è 2D, ma poi ha passato un singolo puntatore e usato come un array 1D all'interno del codice C. Quindi (parzialmente) il mio commento precedente. – Evert

+0

È un po 'più complicato: C++ parte è dll usata da qualche altro software, dovrebbe solo ottenere dati, cambiare il suo formato in numpy e passarlo a python dove tutto il calcolo è fatto (scikit-learn). – klubow

risposta

5

Dovrai copiare i dati in un blocco contiguo di memoria. Per rappresentare un array 2d, numpy non usa una matrice di puntatori agli array 1d. Numpy si aspetta che l'array venga memorizzato in un blocco contiguo di memoria, in (predefinito) row major order.

Se si crea l'array utilizzando PyArray_SimpleNew(...), numpy assegna la memoria per l'utente. È necessario copiare X_test2 in questo array, utilizzando, ad esempio, std::memcpy o std::copy in un ciclo sopra le righe.

Cioè, cambiare questo:

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

a qualcosa di simile:

// 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; 
} 

(Sembra X_test2 è una copia di X_test, così si potrebbe desiderare di modificare il codice qui sopra per copia direttamente da X_test alla serie numpy.)

+0

Grazie, ho appena controllato: sembra funzionare (indago più avanti). A proposito, forse saprai perché chiamare: cols = PyArray_DIM (pValue, 1); non restituisce il numero della colonna, ad es. array.shape [1]? Restituisce 8 quando la matrice numpy è doppia e 4 quando int32? – klubow

+0

Che cos'è 'pValue'? Il primo argomento di 'PyArray_DIM()' deve essere l'oggetto python che contiene l'array numpy, ad es. 'ArgsArray'. –

+0

Questo nel codice allegato alla domanda, pValue = PyObject_CallObject (pFunc, pArgs). Questa è una serie numpy restituita da python – klubow

Problemi correlati