Python / Pandas - Производителност - Изчисляване на % на честотата на стойност в колона

Имам тази рамка от данни, наречена цел:

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