Как удалить столбец из структурированного массива numpy?

У меня есть еще один основной вопрос, на который я не смог найти ответ, но кажется, что это должно быть легко сделать.

Хорошо, представьте, что у вас есть структурированный массив numpy, созданный из csv с первой строкой в ​​качестве имен полей. Массив имеет форму:

dtype([('A', '<f8'), ('B', '<f8'), ('C', '<f8'), ..., ('n','<f8'])

Теперь, скажем, вы хотите удалить из этого массива столбец "ith". Есть ли удобный способ сделать это?

Я бы хотел, чтобы он работал как delete:

new_array = np.delete(old_array, 'i')

Любые идеи?

Ответ 1

Это не совсем один вызов функции, но следующий показывает один способ отбросить i-ое поле:

In [67]: a
Out[67]: 
array([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)], 
      dtype=[('A', '<f8'), ('B', '<f8'), ('C', '<f8')])

In [68]: i = 1   # Drop the 'B' field

In [69]: names = list(a.dtype.names)

In [70]: names
Out[70]: ['A', 'B', 'C']

In [71]: new_names = names[:i] + names[i+1:]

In [72]: new_names
Out[72]: ['A', 'C']

In [73]: b = a[new_names]

In [74]: b
Out[74]: 
array([(1.0, 3.0), (4.0, 6.0)], 
      dtype=[('A', '<f8'), ('C', '<f8')])

Завершена как функция:

def remove_field_num(a, i):
    names = list(a.dtype.names)
    new_names = names[:i] + names[i+1:]
    b = a[new_names]
    return b

Возможно, было бы более естественным удалить заданное имя поля:

def remove_field_name(a, name):
    names = list(a.dtype.names)
    if name in names:
        names.remove(name)
    b = a[names]
    return b

Кроме того, проверьте drop_rec_fields function, которая является частью mlab matplotlib.


Обновление: см. мой ответ в Как удалить столбец из структурированного массива numpy * без копирования его *? для метода создания представления подмножеств поля структурированного массива без создания копии массива.

Ответ 2

Пойдя сюда по ссылке и узнав, что мне нужно знать из ответа Уоррена, я не мог устоять перед публикацией более сжатой версии, добавив возможность эффективно удалять несколько полей за один раз:

def rmfield( a, *fieldnames_to_remove ):
    return a[ [ name for name in a.dtype.names if name not in fieldnames_to_remove ] ]

Примеры:

a = rmfield(a, 'foo')
a = rmfield(a, 'foo', 'bar')  # remove multiple fields at once

Или, если мы действительно собираемся в гольф, это эквивалентно:

rmfield=lambda a,*f:a[[n for n in a.dtype.names if n not in f]]