Python/Pandas – Производительность – Расчет % появления значения в столбце

У меня есть этот фрейм данных, называемый target:

target:

          group
170  64.22-1-00
72   64.22-1-00
121  35.12-3-00
99   64.22-1-00
19   35.12-3-00

Я хочу создать новый столбец с именем group_incidence, который представляет собой отношение частоты появления группы в кадре данных. Он рассчитывается следующим образом:

[total number of times that that 'group' appeared in the group column]/len(target.index)

Это будет выглядеть так:

          group   group_incidence 
170  64.22-1-00               0.6
72   64.22-1-00               0.6
121  35.12-3-00               0.4
99   64.22-1-00               0.6
19   35.12-3-00               0.4

Я смог сделать это с помощью цикла for, однако, поскольку это большой кадр данных, это занимает слишком много времени. Я считаю, что если бы я мог пропустить цикл for, я бы значительно увеличил производительность.

Есть ли способ выполнить ту же операцию, не проходя цикл for?


person aabujamra    schedule 28.06.2017    source источник


Ответы (2)


Подход №1

Один из подходов NumPy:

_,tags, c = np.unique(df.group.values, return_counts=1, return_inverse=1)
df['group_incidence'] = (c/c.sum())[tags]

Пробный запуск -

In [584]: df
Out[584]: 
          group
170  64.22-1-00
72   64.22-1-00
121  35.12-3-00
99   64.22-1-00
19   35.12-3-00

In [585]: _,tags, c = np.unique(df.group.values, return_counts=1, return_inverse=1)

In [586]: df['group_incidence'] = (c/c.sum())[tags]

In [587]: df
Out[587]: 
          group  group_incidence
170  64.22-1-00              0.6
72   64.22-1-00              0.6
121  35.12-3-00              0.4
99   64.22-1-00              0.6
19   35.12-3-00              0.4

Подход № 2

Другой с небольшим беспорядком / низкоуровневыми настройками NumPy с идеей повышения производительности -

def argsort_unique(idx):
    # Original idea : http://stackoverflow.com/a/41242285/3293881 by @Andras
    n = idx.size
    sidx = np.empty(n,dtype=int)
    sidx[idx] = np.arange(n)
    return sidx

def group_ratios_tagged(a):
    sidx = a.argsort()
    b = a[sidx]

    m = np.concatenate(( [False], b[1:] != b[:-1] ))
    sep_idx = np.concatenate(([0], np.flatnonzero(m), [a.size]))
    idx = m.astype(int)
    np.maximum.accumulate(idx, out=idx)

    c = sep_idx[1:] - sep_idx[:-1]
    h = (c/c.sum())[idx]
    out = h[argsort_unique(sidx)]
    return out

Пробный запуск (как использовать) -

In [659]: df = pd.read_clipboard()

In [660]: df
Out[660]: 
          group
170  64.22-1-00
72   64.22-1-00
121  35.12-3-00
99   64.22-1-00
19   35.12-3-00

In [661]: df['group_incidence'] = group_ratios_tagged(df.group.values)

In [662]: df
Out[662]: 
          group  group_incidence
170  64.22-1-00              0.6
72   64.22-1-00              0.6
121  35.12-3-00              0.4
99   64.22-1-00              0.6
19   35.12-3-00              0.4
person Divakar    schedule 28.06.2017

person    schedule
comment
Возможно, len(df) снаружи apply? df.groupby('group')['group'].transform('count')/len(df) - person Zero; 28.06.2017