#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
, не всегда является предпоследней записью для любого заданного идентификатора, то этот код не даст вам правильных результатов.