Pandas применить функцию, которая возвращает несколько значений в строки в pandas dataframe
У меня есть dataframe с индексом timeindex и 3 столбцами, содержащими координаты 3D-вектора:
x y z
ts
2014-05-15 10:38 0.120117 0.987305 0.116211
2014-05-15 10:39 0.117188 0.984375 0.122070
2014-05-15 10:40 0.119141 0.987305 0.119141
2014-05-15 10:41 0.116211 0.984375 0.120117
2014-05-15 10:42 0.119141 0.983398 0.118164
Я хотел бы применить преобразование к каждой строке, которая также возвращает вектор
def myfunc(a, b, c):
do something
return e, f, g
но если я это сделаю:
df.apply(myfunc, axis=1)
В итоге я получаю серию Pandas, элементы которой являются кортежами. Это приложение beacause будет принимать результат myfunc без его распаковки. Как я могу изменить myfunc, чтобы получить новый df с тремя столбцами?
Edit:
Все нижеприведенные решения. Решение Series разрешает имена столбцов, похоже, что решение List выполняется быстрее.
def myfunc1(args):
e=args[0] + 2*args[1]
f=args[1]*args[2] +1
g=args[2] + args[0] * args[1]
return pd.Series([e,f,g], index=['a', 'b', 'c'])
def myfunc2(args):
e=args[0] + 2*args[1]
f=args[1]*args[2] +1
g=args[2] + args[0] * args[1]
return [e,f,g]
%timeit df.apply(myfunc1 ,axis=1)
100 loops, best of 3: 4.51 ms per loop
%timeit df.apply(myfunc2 ,axis=1)
100 loops, best of 3: 2.75 ms per loop
Ответы
Ответ 1
Просто верните список вместо кортежа.
In [81]: df
Out[81]:
x y z
ts
2014-05-15 10:38:00 0.120117 0.987305 0.116211
2014-05-15 10:39:00 0.117188 0.984375 0.122070
2014-05-15 10:40:00 0.119141 0.987305 0.119141
2014-05-15 10:41:00 0.116211 0.984375 0.120117
2014-05-15 10:42:00 0.119141 0.983398 0.118164
[5 rows x 3 columns]
In [82]: def myfunc(args):
....: e=args[0] + 2*args[1]
....: f=args[1]*args[2] +1
....: g=args[2] + args[0] * args[1]
....: return [e,f,g]
....:
In [83]: df.apply(myfunc ,axis=1)
Out[83]:
x y z
ts
2014-05-15 10:38:00 2.094727 1.114736 0.234803
2014-05-15 10:39:00 2.085938 1.120163 0.237427
2014-05-15 10:40:00 2.093751 1.117629 0.236770
2014-05-15 10:41:00 2.084961 1.118240 0.234512
2014-05-15 10:42:00 2.085937 1.116202 0.235327
Ответ 2
Верните Series
, и он поместит их в DataFrame.
def myfunc(a, b, c):
do something
return pd.Series([e, f, g])
У этого есть бонус, который вы можете дать ярлыкам для каждого из полученных столбцов. Если вы вернете DataFrame, он просто вставляет несколько строк для группы.
Ответ 3
Основываясь на отличном ответе на @U2EF1, я создал удобную функцию, которая применяет указанную функцию, которая возвращает кортежи в поле dataframe и расширяет результат вернитесь к фрейму данных.
def apply_and_concat(dataframe, field, func, column_names):
return pd.concat((
dataframe,
dataframe[field].apply(
lambda cell: pd.Series(func(cell), index=column_names))), axis=1)
Использование:
df = pd.DataFrame([1, 2, 3], index=['a', 'b', 'c'], columns=['A'])
print df
A
a 1
b 2
c 3
def func(x):
return x*x, x*x*x
print apply_and_concat(df, 'A', func, ['x^2', 'x^3'])
A x^2 x^3
a 1 1 1
b 2 4 8
c 3 9 27
Надеюсь, что это поможет кому-то.
Ответ 4
Нашел возможное решение, изменив myfunc, чтобы вернуть np.array следующим образом:
import numpy as np
def myfunc(a, b, c):
do something
return np.array((e, f, g))
любое лучшее решение?