#python #pandas
#python #pandas
Вопрос:
У меня есть фрейм данных, подобный этому:
Name GoogleMinutes FacebookMinutes
Alice 10 2
Bob 15 3
Chuck 40 10
Я хочу запустить для каждой ячейки функцию с подписью func(cell_value,name,site_minutes)
.
Другими словами. Я хочу запустить функцию для каждого индекса, имени столбца и значения.
Как я могу это сделать? Я попробовал применить и не сработало.
Редактировать:
Нерабочий пример с применением:
p = PersonDataProvider()
s = SMDataProvider()
df.apply(lambda x: p.get_wealthness(x.index) * s.get_ticket(x.column) * x)
РЕДАКТИРОВАТЬ 2: Важное предупреждение заключается в том, что у меня неизвестное количество столбцов, несмотря на то, что они не показаны в примере.
Комментарии:
1. Можете ли вы опубликовать рабочий пример с приложением?
2. Я отредактировал вопрос.
Ответ №1:
Можете ли вы проверить, работает ли это для вас:
import pandas as pd
def main():
df = pd.DataFrame(
{'Name': ['Alice', 'Bob', 'Chuck', 'pete'], 'GoogleMinutes': [10, 15, 40, 4], 'FacebookMinutes': [2, 3, 10, 7]})
for a in range(df.shape[0]):
cell_value = a
name = df['Name'][a]
site_minutes = (df['GoogleMinutes'][a], df['FacebookMinutes'][a])
func1(cell_value, name, site_minutes)
def func1(cell_value, name, site_minutes):
print(cell_value, name, site_minutes)
return None
if __name__ == '__main__':
main()
Ответ №2:
Похоже, вам нужно внести две простые модификации в ваш код:
a) укажите ось (1 или строку).
б) измените ‘index’ на ‘name’.
Вот так:
names = ['Alice', 'Bob', 'Chuck']
vals = [[10,2],[15,3], [40,10]]
col_names = ['GoogleMinutes', 'FacebookMinutes']
tst = pd.DataFrame(vals, index=names, columns=col_names)
tst['result'] = tst.apply(lambda x: ' '.join((x.name, str(x.GoogleMinutes), str(x.FacebookMinutes))) , axis=1)
Ответ №3:
Решение
Обычно вы могли бы использовать pandas.DataFrame.applymap
для применения вашей функции поэлементно.
import pandas as pd
# df is your dataframe
# df.applymap(lambda x: func(x))
prepare_dataframe(df, axis=0).applymap(lambda cell: func(*cell))
Однако ваш вариант использования немного отличается. Таким образом, вы могли бы использовать функцию custome prepare_dataframe()
для предварительной обработки фрейма данных перед использованием .applymap()
на нем.
Реализация кода — подробный пример
Следующий фрагмент кода был запущен в Google Colab, и кажется, что использование axis=0
, когда number of rows > number of columns
выполняется быстрее.
%time prepare_dataframe(df, axis=0).applymap(lambda cell: func(*cell))
# CPU times: user 5.02 ms, sys: 0 ns, total: 5.02 ms
# Wall time: 4.77 ms
# Or
%time prepare_dataframe(df, axis=1).applymap(lambda cell: func(*cell))
# CPU times: user 13.5 ms, sys: 1 ms, total: 14.5 ms
# # Wall time: 23 ms
Вывод:
| x | y
--------------------------------------------
0 | Out: (0, 'x', 0) | Out: (0, 'y', -5)
1 | Out: (1, 'x', 1) | Out: (1, 'y', -1)
2 | Out: (2, 'x', 2) | Out: (2, 'y', 5)
3 | Out: (3, 'x', 3) | Out: (3, 'y', 13)
4 | Out: (4, 'x', 4) | Out: (4, 'y', 23)
Пользовательские функции
def prepare_dataframe(df, axis=0):
# apply along axis = 0 or 1
# axis = 0 is faster
dff = df.copy()
index = dff.index
columns = dff.columns
nrows, ncols = dff.shape
if axis==1:
dff = dff.T
for idx in index:
dff[idx] = tuple(zip([idx]*ncols, columns, df.loc[idx].values))
dff = dff.T
else:
for col in columns:
dff[col] = tuple(zip(index, [col]*nrows, df[col].values))
return dff
# This is the dummy cell level function
def func(index=0, column='A', value=0):
return f'Out: {(index, column, value)}'
func()
# Out: (0, 'A', 0)
Примечание
В вашем случае func()
будет следующим:
p = PersonDataProvider()
s = SMDataProvider()
def func(index=0, column='A', value=0):
return p.get_wealthness(index) * s.get_ticket(column) * value
Фиктивные данные
import numpy as np
import pandas as pd
x = np.arange(5)
y = x**2 3*x - 5
df = pd.DataFrame({'x': x, 'y': y})
print(df)
# x y
# 0 0 -5
# 1 1 -1
# 2 2 5
# 3 3 13
# 4 4 23
Ссылки
Комментарии:
1. @lispguy: Да, это не работает как есть с .applymap. Ваш вариант использования требует некоторой предварительной обработки. Итак, я обновил решение. Пожалуйста, проверьте сейчас. Это должно сработать у вас.