Доступ к атрибуту элементов в массиве numpy

1

У меня есть полный массив объектов (dtype = object) класса cftime.

In [1]: a
Out[1]: 
array([cftime.DatetimeNoLeap(2000, 1, 1, 11, 29, 59, 999996, 5, 1),
       cftime.DatetimeNoLeap(2000, 1, 2, 11, 29, 59, 999996, 6, 2),
       cftime.DatetimeNoLeap(2000, 1, 3, 11, 29, 59, 999996, 0, 3)],
      dtype=object)

In [2]: type(a[0])
Out[2]: cftime._cftime.DatetimeNoLeap

Каждый из этих объектов имеет атрибут month.

a[0].month
Out[66]: 1

Я хотел бы получить новый массив с такой же формой, но заполненный этим атрибутом для каждого из элементов исходного массива. Что-то вроде b=a.month. Но, очевидно, это не удается, так как является NumPy массива без a month атрибута. Как мне достичь этого результата?

PS: конечно, я мог бы сделать это с простым циклом Python, но я хотел бы следовать полностью тупому подходу:

b=np.zeros_like(a, dtype=int)
for i in range(a.size):
    b[i] = a[i].month
  • 0
    Не тупой ответ, но если не считать, что вы должны использовать понимание цикла / списка. Вы можете создать список, сказав list = [ele] * n , но все элементы ссылаются на одно и то же пространство памяти - изменение любого из них повлияет на остальные. Понимание петли / списка избегает этого.
  • 0
    Почему массив объектов вместо списка? Это не быстрее и не проще.
Показать ещё 2 комментария
Теги:
numpy

2 ответа

2
Лучший ответ

Вы можете использовать np.vectorize, чтобы отобразить функцию на каждый элемент массива. Для этого случая вы можете определить собственную lambda функцию для извлечения месяца каждой записи. lambda x: x.month:

np.vectorize(lambda x: x.month)(a)
array([1, 1, 1])
  • 0
    Использование np.frompyfunc может быть быстрее. vectorize использует его, но имеет тенденцию быть медленнее.
  • 0
    Спасибо за ваш комментарий, посмотрю его :-)
Показать ещё 4 комментария
0

У меня не установлено cftime, поэтому я продемонстрирую обычные объекты datetime.

Сначала создайте массив объектов datetime - ленивый способ, используя собственный тип datetime dtype:

In [599]: arr = np.arange('2000-01-11','2000-12-31',dtype='datetime64[D]')
In [600]: arr.shape
Out[600]: (355,)

Создайте массив dtype объекта из этого:

In [601]: arrO = arr.astype(object)

а также список дат:

In [602]: alist = arr.tolist()

Сроки для регулярного понимания списка:

In [603]: timeit [d.month for d in alist]
20.1 µs ± 62.7 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Понимание списка в массиве dtype объекта обычно немного медленнее (но быстрее, чем понимание списка в обычном массиве):

In [604]: timeit [d.month for d in arrO]
30.7 µs ± 266 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

frompyfunc - вот оно медленнее; в других случаях я вижу это в 2 раза быстрее, чем понимание списка:

In [605]: timeit np.frompyfunc(lambda x: x.month, 1,1)(arrO)
51 µs ± 32.4 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

vectorize (почти) всегда медленнее, чем frompyfunc (даже если для реальной итерации используется frompyfunc):

In [606]: timeit np.vectorize(lambda x: x.month, otypes=[int])(arrO)
76.7 µs ± 123 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Вот образцы массивов и список:

In [607]: arr[:5]
Out[607]: 
array(['2000-01-11', '2000-01-12', '2000-01-13', '2000-01-14',
       '2000-01-15'], dtype='datetime64[D]')
In [608]: arrO[:5]
Out[608]: 
array([datetime.date(2000, 1, 11), datetime.date(2000, 1, 12),
       datetime.date(2000, 1, 13), datetime.date(2000, 1, 14),
       datetime.date(2000, 1, 15)], dtype=object)
In [609]: alist[:5]
Out[609]: 
[datetime.date(2000, 1, 11),
 datetime.date(2000, 1, 12),
 datetime.date(2000, 1, 13),
 datetime.date(2000, 1, 14),
 datetime.date(2000, 1, 15)]

frompyfunc и vectorize лучше всего использовать, когда вы хотите всеобщности вещания и многомерных массивов. Для 1d массивов понимание списка почти всегда лучше.

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

In [610]: timeit np.array([d.month for d in arrO])
50.1 µs ± 36.3 ns per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Чтобы получить лучшую скорость с датами в numpy, используйте datatime64 datatime64 вместо dtype объекта. Это позволяет более широко использовать скомпилированный код.

In [611]: timeit arr = np.arange('2000-01-11','2000-12-31',dtype='datetime64[D]'
     ...: )
3.16 µs ± 51 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

In [616]: arr.astype('datetime64[M]')[::60]
Out[616]: 
array(['2000-01', '2000-03', '2000-05', '2000-07', '2000-09', '2000-11'],
      dtype='datetime64[M]')

Ещё вопросы

Сообщество Overcoder
Наверх
Меню