11

For the sake of learning something new, I am currently trying to reimplement the numpy.mean() function in C. It should take a 3D array and return a 2D array with the mean of the elements along axis 0. I manage to calculate the mean of all values, but don't really know how I would return a new array to Python.

My code so far:

#include <Python.h>
#include <numpy/arrayobject.h>

// Actual magic here:
static PyObject*
myexts_std(PyObject *self, PyObject *args)
{
    PyArrayObject *input=NULL;
    int i, j, k, x, y, z, dims[2];
    double out = 0.0; 

    if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &input))
        return NULL;

    x = input->dimensions[0];
    y = input->dimensions[1];
    z = input->dimensions[2];

    for(k=0;k<z;k++){
        for(j=0;j<y;j++){
            for(i=0;i < x; i++){
                out += *(double*)(input->data + i*input->strides[0] 
+j*input->strides[1] + k*input->strides[2]);
            }
        }
    }
    out /= x*y*z;
    return Py_BuildValue("f", out);
}

// Methods table - this defines the interface to python by mapping names to
// c-functions    
static PyMethodDef myextsMethods[] = {
    {"std", myexts_std, METH_VARARGS,
        "Calculate the standard deviation pixelwise."},
    {NULL, NULL, 0, NULL}
};

PyMODINIT_FUNC initmyexts(void)
{
    (void) Py_InitModule("myexts", myextsMethods);
    import_array();
}

What I understand so far (and please correct me if I'm wrong) is that I need to create a new PyArrayObject, which will be my output (maybe with PyArray_FromDims ?). Then I need an array of adresses to the memory of this array and fill it with data. How would I go about this?

EDIT:

After doing some more reading on pointers (here: http://pw1.netcom.com/~tjensen/ptr/pointers.htm), I achieved what I was aiming at. Now another question arises: Where would I find the origingal implementation of numpy.mean()? I'd like to see how it is, that the python operation is so much faster than my version. I assume it avoids the ugly looping.

Here is my solution:

static PyObject*
myexts_std(PyObject *self, PyObject *args)
{
    PyArrayObject *input=NULL, *output=NULL; // will be pointer to actual numpy array ?
    int i, j, k, x, y, z, dims[2]; // array dimensions ?
    double *out = NULL;
    if (!PyArg_ParseTuple(args, "O!", &PyArray_Type, &input))
        return NULL;

    x = input->dimensions[0];
    y = dims[0] = input->dimensions[1];
    z = dims[1] = input->dimensions[2];
    output = PyArray_FromDims(2, dims, PyArray_DOUBLE);    
    for(k=0;k<z;k++){
        for(j=0;j<y;j++){
            out = output->data + j*output->strides[0] + k*output->strides[1];
            *out = 0;
            for(i=0;i < x; i++){
                *out += *(double*)(input->data + i*input->strides[0] +j*input->strides[1] + k*input->strides[2]);
            }
            *out /= x;
        }
    }
    return PyArray_Return(output);
}
1

1 Answer 1

3

The Numpy API has a function PyArray_Mean that accomplishes what you're trying to do without the "ugly looping" ;).

static PyObject *func1(PyObject *self, PyObject *args) {
    PyArrayObject *X, *meanX;
    int axis;

    PyArg_ParseTuple(args, "O!i", &PyArray_Type, &X, &axis);
    meanX = (PyArrayObject *) PyArray_Mean(X, axis, NPY_DOUBLE, NULL);

    return PyArray_Return(meanX);
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.