Преобразование l oop в pandas операций - PullRequest
1 голос
/ 06 августа 2020

Мне интересно, можно ли следующее более четко выразить с помощью pandas операций по умолчанию, как go сделать это и будет ли это работать быстрее

Данные, которые у меня есть:

data = {}
sz = 200
data["A"] = np.random.choice([1, 2], size=sz, p=[0.6, 0.4])
data["B"] = np.random.choice(
    [1, 2, 3, 4, 5, 6, 7], size=sz, p=[0.7, 0.11, 0.05, 0.05, 0.05, 0.03, 0.01]
)
data["C"] = np.random.normal(loc=0.85, scale=0.57, size=sz)

пример которого выглядит так:

     A  B         C
74   1  1  1.690569
184  2  1  0.808611
67   1  1  0.691865
4    1  1 -0.437749

Код, который у меня есть:

dt = pd.DataFrame.from_dict(data)

groups = dt.groupby("A")
computed = {}
for group in groups:
    subgroup = group[1].groupby("B")
    sum_of_C = group[1]["C"].sum()
    sum_of_subgroup_C = subgroup["C"].sum()
    cell_values = sum_of_subgroup_C / sum_of_C
    computed[group[0]] = cell_values.mul(100).round(1).to_dict()
    computed[group[0]]["tC"] = round(len(group[1]) * group[1]["C"].mean())
    computed[group[0]]["t"] = len(group[1])

Цикл по группам не очень приятный pandas ', но я не уверен, как бы я сделал это, используя всего pandas операций.

1 Ответ

0 голосов
/ 06 августа 2020

Возможным способом является следующий подход:

dt['count'] = 1
dt1= dt.groupby(['A','B'])['C','count'].sum()
dt2 = dt1.groupby('A').sum()    
d1 = (dt1['C']/dt2['C']*100).round(1)

Вычисления выполнены, форматирование для получения аналогичного вам результата:

idx3 = pd.Index([d1.index.values,np.full(d1.shape[0],'t')])

d2 = dt2.loc[:,['C']].round()
d2.index=[d2.index.values,np.full(d2.shape[0],'tc')]
d3 = dt2.loc[:,['count']]
d3.columns = ['C']
d3.index = [d3.index.values,np.full(d3.shape[0],'t')]


T = pd.concat([d1,d2,d3],axis=0).sort_index()

Для больших sz (проверено на sz = 20000000) вышеупомянутый подход на 10-20% быстрее, для sz ниже 200000 ваш подход побеждает вышеуказанное.

У вас также есть одно избыточное вычисление:

computed[group[0]]["tC"] = round(len(group[1]) * group[1]["C"].mean())

Фактически просто :

computed[group[0]]["tC"] = sum_of_C

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

...