Как создать ленивые вычисляемые столбцы dataframe в Pandas
много раз, у меня есть большой фрейм данных df
для хранения основных данных и нужно создать еще много столбцов для хранения производных данных, рассчитанных по столбцам базовых данных.
Я могу сделать это в панд, как:
df['derivative_col1'] = df['basic_col1'] + df['basic_col2']
df['derivative_col2'] = df['basic_col1'] * df['basic_col2']
....
df['derivative_coln'] = func(list_of_basic_cols)
etc. Панды будут вычислять и выделять память для всех производных столбцов сразу.
теперь я хочу иметь ленивый механизм оценки, чтобы отложить вычисление и выделение памяти производных столбцов на действительно нужен момент. Несколько определите lazy_eval_columns как:
df['derivative_col1'] = pandas.lazy_eval(df['basic_col1'] + df['basic_col2'])
df['derivative_col2'] = pandas.lazy_eval(df['basic_col1'] * df['basic_col2'])
это сэкономит время / память, как генератор "yield" Python, если я выдам df['derivative_col2']
команда будет только тригер конкретного расчета и выделения памяти.
как сделать lazy_eval()
в Пандах ? Любой совет/мысль/ref приветствуются.
2 ответов
начиная с 0.13 (выпуск очень скоро), вы можете сделать что-то вроде этого. Это использование генераторов для оценки динамической формулы. Встроенное назначение через eval будет дополнительной функцией в 0.13, см. здесь
In [19]: df = DataFrame(randn(5, 2), columns=['a', 'b'])
In [20]: df
Out[20]:
a b
0 -1.949107 -0.763762
1 -0.382173 -0.970349
2 0.202116 0.094344
3 -1.225579 -0.447545
4 1.739508 -0.400829
In [21]: formulas = [ ('c','a+b'), ('d', 'a*c')]
создайте генератор, который оценивает формулу с помощью eval
; присваивает результат, затем дает результат.
In [22]: def lazy(x, formulas):
....: for col, f in formulas:
....: x[col] = x.eval(f)
....: yield x
....:
в действиях
In [23]: gen = lazy(df,formulas)
In [24]: gen.next()
Out[24]:
a b c
0 -1.949107 -0.763762 -2.712869
1 -0.382173 -0.970349 -1.352522
2 0.202116 0.094344 0.296459
3 -1.225579 -0.447545 -1.673123
4 1.739508 -0.400829 1.338679
In [25]: gen.next()
Out[25]:
a b c d
0 -1.949107 -0.763762 -2.712869 5.287670
1 -0.382173 -0.970349 -1.352522 0.516897
2 0.202116 0.094344 0.296459 0.059919
3 -1.225579 -0.447545 -1.673123 2.050545
4 1.739508 -0.400829 1.338679 2.328644
таким образом, его пользователь определил заказ для оценки (а не по требованию). В теории numba
собирается поддержать это, поэтому панды, возможно, поддерживают это как бэкэнд для eval
(который в настоящее время использует numexpr для немедленной оценки).
мой 2c.
ленивая оценка хороша, но может быть легко достигнута с помощью собственных функций продолжения/генерации python, поэтому создание его в панд, хотя это возможно, довольно сложно, и потребуется действительно хороший usecase, чтобы быть в целом полезным.
вы могли бы подкласс DataFrame
, и добавьте столбец как свойства. Например,
import pandas as pd
class LazyFrame(pd.DataFrame):
@property
def derivative_col1(self):
self['derivative_col1'] = result = self['basic_col1'] + self['basic_col2']
return result
x = LazyFrame({'basic_col1':[1,2,3],
'basic_col2':[4,5,6]})
print(x)
# basic_col1 basic_col2
# 0 1 4
# 1 2 5
# 2 3 6
доступ к собственности (через x.derivative_col1
ниже) называет derivative_col1
функция, определенная в LazyFrame. Эта функция вычисляет результат и добавляет производный столбец в экземпляр LazyFrame:
print(x.derivative_col1)
# 0 5
# 1 7
# 2 9
print(x)
# basic_col1 basic_col2 derivative_col1
# 0 1 4 5
# 1 2 5 7
# 2 3 6 9
обратите внимание, что при изменении базового столбца:
x['basic_col1'] *= 10
производный столбец не автоматически обновлено:
print(x['derivative_col1'])
# 0 5
# 1 7
# 2 9
но если вы получаете доступ к свойству, значениям вычисляются:
print(x.derivative_col1)
# 0 14
# 1 25
# 2 36
print(x)
# basic_col1 basic_col2 derivative_col1
# 0 10 4 14
# 1 20 5 25
# 2 30 6 36