Как объединить структурный массив с дубликатами - PullRequest
1 голос
/ 21 марта 2019

R пользователь здесь, и я пытаюсь использовать свой первый проект на Python, чтобы воспользоваться Numba.Я читал, что Нумба очень хорошо работает с Нампи, но не очень хорошо с Пандами, поэтому я стараюсь избегать Панд.Мой текущий вопрос на самом деле не имеет ничего общего с Numba, но я хотел упомянуть его как причину, по которой я избегал панд.

У меня есть два структурированных массива Numpy, один со многими дубликатами.Я пытаюсь присоединиться к ним, используя функцию «numpy.lib.recfunctions.join_by», но в документации прямо говорится, что дублирование вызывает проблемы.Кто-нибудь может порекомендовать какие-либо обходные пути для всех моих дубликатов?

Вот пример, похожий на мою ситуацию:

import numpy as np
import numpy.lib.recfunctions as rfn

a = np.zeros(4, dtype={'names':('name', 'age'),
                       'formats':('U10','f8')})
a['name'] = ['Alex', 'Billy', 'Charlie', 'Dave']
a['age'] = [25, 25, 75, 75]

b = np.zeros(2, dtype={'names':('age', 'senior'),
                       'formats':('f8', 'i4')})
b['age'] = [25, 75]
b['senior'] = [0, 1]

c = rfn.join_by('age', a, b, jointype='leftouter', usemask=False)

print(c)
[(25., 'Alex',      0) (75., 'Billy',      1) (75., 'Charlie', 999999)
(75., 'Dave', 999999)]

Это (1) изменяет «возраст» Билли с 25 до 75 и(2) дает «старшее» значение 999999 для Чарли и Дейва.

У кого-нибудь есть обходной путь для ограничения дубликатов этой функции?Заранее спасибо.

Ответы [ 2 ]

0 голосов
/ 21 марта 2019

Под прикрытием повторные функции обычно создают новый dtype и «пустой» массив результатов.Затем они копируют значения по имени поля.Я не изучал join_by, но могу представить, что ваше объединение выглядит так:

In [11]: a.dtype                                                                          
Out[11]: dtype([('name', '<U10'), ('age', '<f8')])
In [12]: b.dtype                                                                          
Out[12]: dtype([('age', '<f8'), ('senior', '<i4')])
In [13]: b.dtype[1]                                                                       
Out[13]: dtype('int32')
In [14]: b.dtype.descr                                                                    
Out[14]: [('age', '<f8'), ('senior', '<i4')]

In [16]: dt = np.dtype(a.dtype.descr+[b.dtype.descr[1]])                                  
In [17]: dt                                                                               
Out[17]: dtype([('name', '<U10'), ('age', '<f8'), ('senior', '<i4')])

In [18]: e = np.zeros(a.shape, dt)                                                        
In [19]: for name in a.dtype.names: 
    ...:     e[name] = a[name] 
    ...:                                                                                  

In [21]: e                                                                                
Out[21]: 
array([('Alex', 25., 0), ('Billy', 25., 0), ('Charlie', 75., 0),
       ('Dave', 75., 0)],
      dtype=[('name', '<U10'), ('age', '<f8'), ('senior', '<i4')])

С небольшим методом проб и ошибок я нашел такой способ соединения возрастов b с a (сейчас e) единицы:

In [23]: e['age'][:,None]==b['age']                                                       
Out[23]: 
array([[ True, False],
       [ True, False],
       [False,  True],
       [False,  True]])
In [25]: np.where(Out[23])                                                                
Out[25]: (array([0, 1, 2, 3]), array([0, 0, 1, 1]))

Теперь просто скопируйте соответствующие «старшие» значения из b в e:

In [27]: e['senior'][Out[25][0]] = b['senior'][Out[25][1]]                                
In [28]: e                                                                                
Out[28]: 
array([('Alex', 25., 0), ('Billy', 25., 0), ('Charlie', 75., 1),
       ('Dave', 75., 1)],
      dtype=[('name', '<U10'), ('age', '<f8'), ('senior', '<i4')])

Базовая логика независит от этих структурированных массивов.У нас точно так же есть отдельные 1d-массивы names, ages, senior_category_age и т. Д.

recfunctions не находит большого применения - как видно из отдельной упаковки, ииз ограниченных вопросов ТАК.Однако недавние изменения в многополевом индексировании, я думаю, повысят его использование, по крайней мере, для вновь добавленных функций.

https://docs.scipy.org/doc/numpy/user/basics.rec.html#accessing-multiple-fields

0 голосов
/ 21 марта 2019

Почему вместо вступления не делать сравнения?Это работает намного лучше в вашем примере.

Я понимаю, что это не будет работать для произвольных объединений, где у вас есть набор ключей, которые должны отображаться на значения.Там я рекомендую вам перебрать ключи и создать массив с нуля, начиная с пустого массива, заполненного NaN, и используя np.where, чтобы найти и заменить значения в массиве.

Используя этот начальный код:

import numpy as np
import numpy.lib.recfunctions as rfn

a = np.zeros(4, dtype={'names':('name', 'age'),
                       'formats':('U10','f8')})
a['name'] = ['Alex', 'Billy', 'Charlie', 'Dave']
a['age'] = [25, 25, 75, 75]

, вы можете сделать:

d = rfn.append_fields(a, names='senior', data=(a['age'] >= 65).astype(int))
print(d)

, что приведет к:

[('Alex', 25.0, 0) ('Billy', 25.0, 0) ('Charlie', 75.0, 1) ('Dave', 75.0, 1)]

Основная причина использования Numba - скоростьдо кода Python.У Numpy и Pandas уже есть эти ускорения ниже капота.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...