Повышение эффективности агрегации в Pandas

У меня есть два фрейма данных в этой проблеме. Я хочу добавить столбец в заем_дф, который агрегирует по recharge_df. Таким образом, для каждой предоставленной ссуды я хочу получить средние пополнения заемщика до даты получения ссуды (в данном случае за 90 дней). Затем я добавлю этот новый столбец в заем_дф. Мой код ниже работает, но работает медленно. Есть идеи, как сделать это супер эффективным?

def mean_rec_func(msisdn,date,advance_id,window, name):
"""Returns mean recharges within a specified number of days prior to loan being taken
Keyword Arguments:
msisdn -- APF_MSISDN for loan (this is like customer ID)
date -- APF_DATE on which loan taken
advance_id -- APF_ADVANCE_ID for loan
window -- number of days to look back(int)
name -- name of the newly computed stat
"""
mean_rec = recharge_df.loc[(recharge_df['APF_MSISDN'] == msisdn) &
                          (recharge_df['APF_DATE']<date)
                          & (recharge_df['APF_DATE']>=date - datetime.timedelta(days = window))
                          ]['APF_AMOUNT'].mean()
return pd.Series([advance_id,msisdn,mean_rec], index=['APF_ADVANCE_ID', 'APF_MSISDN', name])
# Mean recharge over last 90 days
mean_recharge_90 = loan_df.apply(lambda row: mean_rec_func(row['APF_MSISDN'], row['APF_DATE'],
                                                         row['APF_ADVANCE_ID'],
                                                         window = 90,
                                                         name  = "MEAN_RECHARGE_90"), axis = 1)

Обновлено: Повышение эффективности агрегации в Pandas

Пожалуйста, предоставьте минимальный воспроизводимый пример. Здесь это означает исправление отступов в коде, предоставление некоторых входных данных, отображение текущего / желаемого результата для этих входных данных. Никаких изображений / ссылок, только текст.

jpp 26.08.2018 00:51
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
1
204
1

Ответы 1

Рассмотрим решение SQL, поскольку ваша логика преобразуется в следующий запрос с коррелированным агрегатным подзапросом (который, по общему признанию, также является дорогостоящим типом запроса, поскольку агрегаты запускаются для каждой внешней строки запроса, аналогично циклу pandas apply).

SELECT l.*, 
       (SELECT AVG([APF_AMOUNT]) FROM recharge_df r
        WHERE r.[APF_DATE] >= date(l.[APF_DATE], '-90 day') 
          AND r.[APF_DATE] < l.[APF_DATE]
          AND r.[APF_MSISDN] = l.[APF_MSISDN]) AS mean_recharge_90
FROM loan_df l

В pandas вы можете использовать модуль pandasql, который запускает экземпляр SQLite в памяти:

from pandasql import sqldf

pysqldf = lambda q: sqldf(q, globals())

sql = """SELECT l.*, 
            (SELECT AVG([APF_AMOUNT]) FROM recharge_df r
             WHERE r.[APF_DATE] >= date(l.[APF_DATE], '-90 day') 
               AND r.[APF_DATE] < l.[APF_DATE]
               AND r.[APF_MSISDN] = l.[APF_MSISDN]) AS mean_recharge_90
         FROM loan_df l"""

output_df = pysqldf(q)

Ниже представлена ​​расширенная версия, которая работает под капотом pandasql, взаимодействуя с вызовами импорта / экспорта SQLAlchemy и pandas: read_sql и to_sql.

from sqlalchemy import create_engine

# IN-MEMORY DATABASE (NO PATH SPECIFIED)
engine = create_engine('sqlite://')

# EXPORT DATAFRAMES
recharge_df.to_sql("recharge_tbl", con=engine, if_exists='replace')
loan_df.to_sql("loan_tbl", con=engine, if_exists='replace')

sql = """SELECT l.*, 
            (SELECT AVG([APF_AMOUNT]) FROM recharge_tbl r
             WHERE r.[APF_DATE] >= date(l.[APF_DATE], '-90 day') 
               AND r.[APF_DATE] < l.[APF_DATE]
               AND r.[APF_MSISDN] = l.[APF_MSISDN]) AS mean_recharge_90
         FROM loan_tbl l"""

# IMPORT QUERY RESULT
output_df = pd.read_sql(strSQL, engine)

# IN-MEMORY DATABASE DESTROYED
engine.dispose()                       

Спасибо за ответ. К сожалению, это не решит проблему. Проблема в том, что я работаю с двумя фреймами данных, и мне нужно, чтобы агрегация recharge_df относилась к дате в заимствовании_df.

mish1818 26.08.2018 16:54

См. Обновленное решение с использованием SQL. Может быть, есть прирост производительности при использовании механизма запросов.

Parfait 26.08.2018 19:23

Другие вопросы по теме