C-numpy: установка типа данных для строк фиксированной ширины?

Я работаю с некоторыми данными, которые представлены в C в виде строк. Я хотел бы вернуть массив numpy на основе этих данных. Однако я бы хотел, чтобы массив имел dtype='SX', где X — число, определяемое во время выполнения.

Пока я копирую данные в C так:

    buffer_len_alt = (MAX_WIDTH)*(MAX_NUMBER_OF_ITEMS);
    output_buffer = (char *) calloc(sizeof(char), buffer_len_alt);
    column = PyArray_SimpleNewFromData(1, &buffer_len_alt, NPY_BYTE, output_buffer);
    if (column == NULL){
        return (PyObject *) NULL;
    }
    /* Put strings of length MAX_WIDTH in output_buffer */
    return column;

Как видите, я говорю PyArray_SimpleNewFromData, что «column» — это одномерный массив байтов, поэтому, когда указатель, который мы назвали «column», становится объектом python «col», мы видим это:

print(col)
>> array([48,  0,  0, 50, 48, 48, 48,  0,  0, 50, 48, 48, 50, 48, 48, 48,  0, 0], dtype=int8)
print(col.view('S3'))
>> array([b'0', b'200', b'0', b'200', b'200', b'0'], dtype='|S3')

Префикс «b» говорит мне, что они по-прежнему интерпретируются как массивы байтов, но вместо этого я хочу иметь строки «0», «200» и т. д. В этом примере строки представляют собой цифры, но это не всегда так.

Я знаю, что могу индивидуально вызвать b'200'.decode(format), чтобы превратить каждый отдельный байтовый объект в строку, но весь смысл написания расширения C для numpy заключался в том, чтобы запустить все циклы в C. Старый chararray Интерфейс (теперь устарел?) также предоставил метод array.decode, который будет декодировать каждую последовательность в массиве, но опять же объекты, возвращаемые интерфейсом numpy-C, являются просто ndarrays.

Вопрос Какой typenum я должен передать SimpleNewFromData вместо NPY_BYTE, чтобы python получил массив с правильной информацией о типе (например, dtype='S5')?

В качестве альтернативы, если ни один typenum не достигает этого с помощью SimpleNewFromData, то, возможно, мне нужно использовать SimpleNewFromDescr, но я не знаю, как правильно установить параметры PyArray_Descr, и документация действительно неоднородна по этому вопросу, поэтому я был бы очень признателен за любую форму руководство.


person Max    schedule 31.08.2016    source источник
comment
Тип S5 хранится как 5 байт. U5 как 4*5 байт. В py3 unicode является строкой по умолчанию. Строки байтов отображаются с флагом b. В py2 дополнительный флаг получает юникод.   -  person hpaulj    schedule 31.08.2016


Ответы (1)


Я не знаком с частью C вашего кода, но похоже, что вы путаете представление байтовых строк и строк Unicode. Отображение b'200' указывает на то, что вы работаете в Py3, где unicode является типом строки по умолчанию.

В сеансе Py3:

Необработанные байты:

In [482]: x=np.array([48,  0,  0, 50, 48, 48, 48,  0,  0, 50, 48, 48, 50, 48, 48, 48,  0, 0], dtype=np.int8)

просмотрены 3-байтовые строки. В сеансе PY2 b не будет использоваться. Но вид тот же.

In [483]: x.view('S3')
Out[483]: 
array([b'0', b'200', b'0', b'200', b'200', b'0'], 
      dtype='|S3')

view не изменяет буфер данных, но astype может преобразовывать элементы по мере необходимости и создавать новый массив с новым буфером данных.

In [484]: x.view('S3').astype('U3')
Out[484]: 
array(['0', '200', '0', '200', '200', '0'], 
      dtype='<U3')
In [485]: x.view('S3').astype('U3').view(np.uint8)
Out[485]: 
array([48,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 50,  0,  0,  0, 48,
        0,  0,  0, 48,  0,  0,  0, 48,  0,  0,  0,  0,  0,  0,  0,  0,  0,
        0,  0, 50,  0,  0,  0, 48,  0,  0,  0, 48,  0,  0,  0, 50,  0,  0,
        0, 48,  0,  0,  0, 48,  0,  0,  0, 48,  0,  0,  0,  0,  0,  0,  0,
        0,  0,  0,  0], dtype=uint8)

Версия Unicode имеет 72 байта в буфере, по 4 байта на символ.

np.char все еще существует, но в основном для применения строковых методов к массивам типов S и U. np.char.decode делает то же самое, что и astype.

In [489]: np.char.decode(x.view('S3'))
Out[489]: 
array(['0', '200', '0', '200', '200', '0'], 
      dtype='<U3')
person hpaulj    schedule 31.08.2016