Представьте, что у нас есть такой DataFrame:
df = pd.DataFrame(np.array([[284.77, 234.37, 243.8, 84.36, 0., 0., 0., 55.04, 228.2, 181.97, 0., 0.],
[13.78, 0., 38.58, 33.16, 0., 38.04, 74.02, 45.74, 27.2, 9.19, 0., 0.],
[88.66, 255.72, 323.19, 7.24, 0., 73.38, 45.73, 0., 0., 77.39, 26.57, 279.34],
[0., 0., 34.42, 9.16, 0., 43.4, 42.17, 123.69, 60.5, 25.47, 72.32, 7.29],
[320.6, 1445.56, 856.23, 371.21, 0., 244.22, 134.58, 631.59, 561.82, 1172.44, 895.68, 186.28],
[0., 0., 32.29, 1000.91, 0., 680., 585.46, 466.6, 0., 493.48, 157.1, 125.31]]),
columns=[1,2,3,4,5,6,7,8,9,10,11,12])
df['Lists_to_sum'] = [[1,2,3,4],
[4,6,8,9,10,11],
[2],
[3,4,5,6,7,8,9,10,11],
[1,2,3,4,5,6,7,8,9],
[2,3,4,5,6,7,8,9,10,11,12],]
Наша цель — добавить столбец с суммой каждой строки, но есть загвоздка: мы просто хотим сложить столбцы, которые есть в списках каждой строки, представленной в столбце «Lists_to_sum», то есть каждая строка имеет будет добавлен другой набор столбцов
Окончательный DataFrame должен выглядеть так:
Я уже упоминал, что был подвох? На самом деле их два: для решения нам нужна векторизованная производительность.
Я попытался решить эту проблему с помощью наивного подхода, который в некоторой степени сработал: он дает мне желаемые результаты. Но он работает хуже всего, поскольку код перебирает каждую строку. Для крошечного DataFrame, такого как в примере, это нормально, но реализация этого решения на огромном DataFrame с десятками миллионов строк — это уже другая история.
for n,m,i in zip(df.index, df['Lists_to_sum'], range(0, df.shape[0])):
df.at[n,'SUM_per_ROW'] = df[m][i:i+1].sum(axis=1)
print('{} de {}'.format(i+1, df.shape[0]))
Итак, мне интересно, есть ли лучший способ решить эту проблему... Можете ли вы мне помочь?
Код
создать условие с помощью explode
и get_dummies
(и группировать по любому) и логической маскировки (и суммы)
cond = pd.get_dummies(df['Lists_to_sum'].explode()).groupby(level=0).any()
df['SUM_per_ROW'] = df[cond].sum(axis=1)
дф
Вы можете использовать numpy
:
sums = np.zeros(df.shape[0])
for i, indices in enumerate(df["Lists_to_sum"].to_list()):
sums[i] = df.loc[i, indices].sum()
df["SUM_per_ROW"] = sums
1 2 3 4 5 6 7 8 9 10 11 12 Lists_to_sum SUM_per_ROW
0 284.77 234.37 243.80 84.36 0.0 0.00 0.00 55.04 228.20 181.97 0.00 0.00 [1, 2, 3, 4] 847.30
1 13.78 0.00 38.58 33.16 0.0 38.04 74.02 45.74 27.20 9.19 0.00 0.00 [4, 6, 8, 9, 10, 11] 153.33
2 88.66 255.72 323.19 7.24 0.0 73.38 45.73 0.00 0.00 77.39 26.57 279.34 [2] 255.72
3 0.00 0.00 34.42 9.16 0.0 43.40 42.17 123.69 60.50 25.47 72.32 7.29 [3, 4, 5, 6, 7, 8, 9, 10, 11] 411.13
4 320.60 1445.56 856.23 371.21 0.0 244.22 134.58 631.59 561.82 1172.44 895.68 186.28 [1, 2, 3, 4, 5, 6, 7, 8, 9] 4565.81
5 0.00 0.00 32.29 1000.91 0.0 680.00 585.46 466.60 0.00 493.48 157.10 125.31 [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 3541.15
Или pandas.apply
:
df["SUM_per_ROW"] = df.apply(
lambda row: sum(row[col] for col in row["Lists_to_sum"]), axis=1
)
1 2 3 4 5 6 7 8 9 10 11 12 Lists_to_sum SUM_per_ROW
0 284.77 234.37 243.80 84.36 0.0 0.00 0.00 55.04 228.20 181.97 0.00 0.00 [1, 2, 3, 4] 847.30
1 13.78 0.00 38.58 33.16 0.0 38.04 74.02 45.74 27.20 9.19 0.00 0.00 [4, 6, 8, 9, 10, 11] 153.33
2 88.66 255.72 323.19 7.24 0.0 73.38 45.73 0.00 0.00 77.39 26.57 279.34 [2] 255.72
3 0.00 0.00 34.42 9.16 0.0 43.40 42.17 123.69 60.50 25.47 72.32 7.29 [3, 4, 5, 6, 7, 8, 9, 10, 11] 411.13
4 320.60 1445.56 856.23 371.21 0.0 244.22 134.58 631.59 561.82 1172.44 895.68 186.28 [1, 2, 3, 4, 5, 6, 7, 8, 9] 4565.81
5 0.00 0.00 32.29 1000.91 0.0 680.00 585.46 466.60 0.00 493.48 157.10 125.31 [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] 3541.15
Отлично, Панда Ким! Он отлично работал с фреймом данных с 1,2 миллионами строк (43 секунды на выполнение). Большое спасибо!