Как я могу условно найти более раннюю дату после заданной даты во фрейме данных?

#python #dataframe

#python #фрейм данных

Вопрос:

Я пытаюсь выполнить поиск между двумя фреймами данных для серии идентификаторов.

У каждого идентификатора в lookup_df есть дата, в которую он был опубликован, и мне нужно найти последнюю дату в ref_df относительно даты lookup_df.

В приведенном ниже примере идентификатор 123 lookup_df был опубликован 20200218, поэтому из дат в ref_df мне нужно просмотреть только те, у которых есть идентификатор 123, и найти последнюю дату перед этим, которая будет 20200201.

Я пробовал различные циклы и не могу заставить это работать, а реальная база данных насчитывает более 600 тыс. строк, поэтому я боюсь, что мой текущий подход, приведенный ниже, к созданию временного DF для последующего выполнения цикла, приведет к непрактичному времени выполнения для завершения этого.

 ref_df = pd.DataFrame({'ID':[123,123,123,345,345,345],'version':['version1','version2','version3','version4','version5','version6'],
                       'date effective from':['20200101','20200201','20200301','20200401','20200501','20200601',]})
print(ref_df)

lookup_df = pd.DataFrame({'ID':[123,345],'date':['20200218','20200522']})
print(lookup_df)

for index, row in lookup_df.iterrows():
    temp_df = ref_df[ref_df['ID']==row['ID']]
    for index2, row2 in temp_df:
        #some code here to find the right date?!

  

Редактировать — приношу извинения за то, что не могу напрямую отображать таблицы, это связано с моим незнанием того, как форматировать мои вопросы — указатели приветствуются!

Комментарии:

1. Спасибо за различные предложения ниже. Я попробовал несколько и получаю ошибку «IndexError: одиночный позиционный индексатор выходит за рамки» после примерно десяти итераций, когда я запускаю его в основной базе данных. Заранее спасибо за любую помощь в моем понимании, почему это может быть!!!

Ответ №1:

Вот вариант, использующий last_valid_index() :

 idx = [ref_df.loc[ref_df['ID'] == value].last_valid_index() -
   1 for value in lookup_df['ID']]

print(ref_df.loc[idx])
  

РЕДАКТИРОВАТЬ: удаление циклов

 mask = ref_df['ID'].isin(lookup_df['ID'])
new_df = ref_df[mask].groupby('ID').apply(lambda x: x.iloc[-2])
print(new_df)
  

Комментарии:

1. Большое вам спасибо за это — я рассмотрю это, как только попробую другое предложенное решение. Приветствия!

2. Я запустил это в основной базе данных час назад, и это все еще продолжается, поскольку в базе данных 600 Тыс. строк. Я не думаю, что вы знаете, как бы я понял, какой прогресс достигнут за это время, или сократил продолжительность и назначил ответ непосредственно lookup_df? Еще раз спасибо за вашу помощь, очень ценится!!!

3. Это завершило выполнение и, похоже, полностью решает проблему!! Большое вам спасибо за вашу помощь GhandiFloss — помечено как решение. Еще раз спасибо за то, что помогли мне решить мою проблему и пополнили мои знания Python. Вы, сэр / мадам, джентльмен и ученый. Искреннее спасибо!!!

4. Привет, чизбургер. Спасибо за ваши добрые комментарии. Я добавил обновление, если ваш look_up большой, что должно быть намного быстрее.

Ответ №2:

Измените date effective from на date и попробуйте это:

 for index, row in lookup_df.iterrows():
    result = ref_df.loc[(ref_df['ID'] == row['ID']) amp; (ref_df['date'] < row['date'])].iloc[-1,:].values[-1]
    print(result)
  

Вывод:

 20200201
20200501
  

Комментарии:

1. Спасибо, я экспериментирую с этим сейчас — похоже, что он печатает результат. Похоже, что это может быть довольно медленно, хотя это может быть просто функция печати. знаете ли вы, как я мог бы выполнить операцию быстрее, непосредственно через фрейм данных или векторизацию, учитывая размер базы данных? Еще раз спасибо за вашу помощь, очень ценится!!!

2. Дополнительно. и в соответствии с другим решением ниже — я получаю сообщение об ошибке при преобразовании его в основную базу данных: «Ошибка индекса: одиночный позиционный индексатор выходит за пределы». Вы знаете, почему это может быть?

3. @Cheeseburger это означает, что выбранные записи для одного из идентификаторов отсутствуют.

Ответ №3:

Сначала вы можете получить «последнюю» дату из lookup_df , используя следующее:

 latest = lookup_df[lambda x: x.ID == ID]['date'].iloc[0]
  

С этой «последней» датой мы можем выполнить другой запрос ref_df для получения желаемого результата:

 result = ref_df[lambda x: x.ID == ID]
    [lambda x: x['date effective from'] < date]
    ['date effective from']
    .iloc[-1]
    
  

Чтобы сделать то же самое для всех идентификаторов в lookup_df , оберните это в свои коды следующим образом:

 for _, row in lookup_df.iterrows():
    ID, date = row['ID', 'date']

    result = ref_df[lambda x: x.ID == ID]
        [lambda x: x['date effective from'] < date]
        ['date effective from']
        .iloc[-1]
        
  

Вам не нужно перебирать все строки в ref_df , используйте фильтры, подобные следующим:

 df[<some condition here>]
  

или, например:

 df[df['idx'] > 3]
  

возвращает все строки, в df которых idx столбец больше 3.

Комментарии:

1. Что здесь ID? Это выдаст ошибку, поскольку вы ее не определили

2. Опубликованные мной коды работают только для одного идентификатора. Вы можете обернуть мои коды в свои коды, которые повторяются через lookup_df. Позвольте мне отредактировать мой ответ.

3. Спасибо за этот ответ, Кельвин. Я пробую это сейчас, поскольку у меня возникли проблемы с другими ответами. Можете ли вы объяснить, как я могу «использовать фильтры, подобные следующим», на которые дан этот ответ, чтобы мне не нужно было перебирать весь фрейм данных, а просто назначить его прямо в другой столбец фрейма данных? Такое чувство, что это полностью решило бы эту проблему!!

4. Дополнительно — я получаю сообщение об ошибке при преобразовании его в основную базу данных: «IndexError: одиночный позиционный индексатор находится вне пределов». Вы знаете, почему это может быть?

5. Ошибка возникает, когда один из идентификаторов не имеет записи в, ref_df где date effective from значение раньше, чем date в lookup_df . Насколько я могу видеть, ответ @GhandiFloss не проверяет это. Если дата, которую вы хотите получить от ref_df , не всегда является предпоследней записью для любого заданного идентификатора, то этот код не даст вам правильных результатов.