Я пишу расширение c, чтобы вычислить его стандартное отклонение. Производительность важна, поскольку она будет выполняться на больших наборах данных. Мне сложно понять, как получить значение pyobject, как только я получу элемент из списка. Это мой первый раз, когда я пишу c-расширение для python, и любая помощь приветствуется. По-видимому, я не знаю, как правильно использовать кнопку примера кода: (
Это то, что у меня есть до сих пор:
#include <Python.h>
static PyObject*
func(PyObject *self, PyObject *args)
{
PyObject *list, *item;
Py_ssize_t i, len;
if (!PyArg_UnpackTuple(args, "func", 1, 1, &list)){
return NULL;
}
printf("hello world\n");
Py_INCREF(list);
len = PyList_GET_SIZE(list);
for (i=0;i<len;i++){
item = PyList_GET_ITEM(list, i);
PyObject_Print(item,stdout,0);
}
return list;
}
static char func_doc[] = "This function calculates standard deviation.";
static PyMethodDef std_methods[] = {
{"func", func, METH_VARARGS, func_doc},
{NULL, NULL}
};
PyMODINIT_FUNC
initstd(void)
{
Py_InitModule3("std", std_methods, "This is a sample docstring.");
}
Вы можете изобретать колесо. Для Python существует несколько научных вычислительных библиотек, таких как SciPy и Numpy, которые в основном представляют собой оболочки вокруг библиотек C, которые реализуют такие функции, как стандартное отклонение.
Как только у вас есть item
, вы можете получить его значение с плавающей точкой PyNumber_Float:
PyObject* floatitem = PyNumber_Float(item);
Теперь вам нужно проверить и выйти с ошибкой (if(!floatitem) return 0
- или goto
в место, где вы уменьшаете все, что у вас может быть увеличено в предыдущей части кода, например, в вашем случае list
). Если ошибка отсутствует, PyFloat_AsDouble дает требуемое значение double
для использования в остальной части вашего C-кодированного цикла:
double ditem = PyFloat_AsDouble(floatitem);
после чего вы можете уменьшить floatitem
и пойти своим весельем. Не беспокойтесь о чрезмерных затратах на конвертацию в PyNumber_Float
- их не будет, если вы сначала передадите список поплавков;-). Если вы все еще беспокоитесь (скорее всего, допустите ошибку, если кто-то пропустит неплатеж, требующий преобразования), вы можете использовать PyFloat_Check
, если вы настаиваете (но я бы предложил по крайней мере специальные элементы int
и long
если вы не хотите по-настоящему недоумевать и недовольных пользователей;-). В аналогичном ключе я также настоятельно рекомендую изучать и использовать PySequence_Fast и друзей, а не поразительных пользователей, специально требуя списков, а не другие типы последовательностей! -).
Считаете ли вы использование cython, чтобы написать расширение. Это идеально подходит для этого типа вещей
Просто упомянем, что есть почти наверняка лучший способ, чем писать расширение C.
Первый вариант - использовать NumPy. В комментарии, который вы указали на другой ответ, упоминается, что преобразовать список в массив очень дорого. Это может быть правдой, если расчет стандартного отклонения - это единственный бит, который вы делаете с данными, которые маловероятны.
Запрет на это, я бы пошел на Cython. Здесь - сравнение Cython и NumPy. В этом случае Cython в этом случае превосходит NumPy, но, что более важно, код, реализованный для csum
, может быть тривиально изменен для вычисления стандартного отклонения.
Если вам нужна простая статистика по большим наборам данных, вы можете произвольно пробовать подмножество данных и принимать среднее и стандартное отклонение от этого. У этого будет "стандартная ошибка" приближения, и чем больше образцов вы возьмете, тем меньше будет. Если вам не нужна высокая точность статистики, вам не нужно читать все данные.
Этот метод будет ограничен количеством элементов в списке.
Другая конструкция будет содержать текущее количество и позволит добавлять точки до тех пор, пока вы не переполните двойной.