Python Pandas заполнить датафрейм данными из другого датафрейма
Есть сгруппированный датафрейм, в котором хранятся пары уникальных чисел и счетчик с количеством повторений каждой пары. Дополнительно есть 2 колонки, в которых храниться каждое число из пары.
Так же имеется второй датафрейм, в котором есть числа.
Что необходимо: во второй датафрейм добавить 2 колонки, в в каждую из которых будут внесены 2 числа, с которыми указанное число было в паре максимальное количество раз в первом df.
Пробовал написать функцию: берет число из второй таблицы использует его в качестве маски для отбора строк из первого датафрейма. Так как первый df отсортирован по убыванию совпадений, то верхние 2 строки с примененной маской будут содержать совпадение и всегда будут самыми популярными: первая строка для получения первой рекомендации, вторая строка - для второй
Далее пытаюсь вернуть число != поданному: если поданное число в колонке first, то возвращаем second, иначе возвращаем first. Вот кусок кода без условий разбивки 2 строки, только с одной. Мне бы понять: как его заставить работать?)))
def get_rec(n):
mask1 = recomedations['first'] == n
mask2 = recomedations['second'] == n
temprec = recomedations[mask1 | mask2].head(1)
if temprec['first'] == n:
return temprec['second']
else:
return temprec['first']
Ответы (3 шт):
Исходные данные для примера:
df1 = pd.DataFrame({'pairs': [(551, 566), (515, 551), (489, 551), (523, 551), (566, 794)],
'first': [566, 551, 551, 551, 794],
'second': [551, 515, 489, 523, 566],
'count': [797, 417, 311, 304, 290]})
df2 = pd.DataFrame({'resource_id': list(range(356, 1201))})
Решение:
df1_filt = df1.groupby('first')['count'].nlargest(2).droplevel(1).reset_index()
keys = list(df1_filt.columns.values)
i1 = df1.set_index(keys).index
i2 = df1_filt.set_index(keys).index
df1_filt = df1[i1.isin(i2)]
df1_filt['numb'] = df1_filt.groupby('first').cumcount()+1
final = df2.merge(df1_filt.pivot(index='first', columns='numb', values='second'),
left_on='resource_id', right_on='first')
Вывод для пример:
print(final)
resource_id 1 2
0 551 515.0 489.0
1 566 551.0 NaN
2 794 566.0 NaN
при исходных
df1 = pd.DataFrame({'pairs': [(489, 566), (515, 551), (489, 551), (523, 551), (566, 794)],
'first': [566, 551, 551, 551, 794],
'second': [489, 515, 489, 523, 566],
'count': [797, 417, 311, 304, 290]})
df2 = pd.DataFrame({'resource_id': list(range(489, 794))})
можно так попробовать:
res = df2["resource_id"].apply(lambda x: [df1[["first", "second"]]
.iloc[i,j-2] for i, j in np.argwhere(df1==x)[:2]])
df2[[1,2]] = pd.DataFrame(res.to_list(), index = df2.index)
df2 теперь:
resource_id 1 2
0 489 566.0 551.0
1 490 NaN NaN
...
25 514 NaN NaN
26 515 551.0 NaN
27 516 NaN NaN
...
33 522 NaN NaN
34 523 551.0 NaN
и т. д.
Еще вариация на тему. Алгоритм, наверное, похож на подход @KirillKondratenko, но другая реализация и другой результат на тестовом фрейме.
- Размножаем первый фрейм, соединяя исходный и модифицированный (в котором колонки first и second поменяны местами). Это для того, чтобы в колонке first были все возможные значения.
- Группируем по first и делаем вспомогательную колонку c рангом по count (в обратном порядке) - самые большие значения будут иметь ранги 1 и 2.
- Соединяем фрейм 2 с фреймом 1 (отфильтрованным по рангу до 3) через 'resource_id' - 'first' и выворачиваем результат, чтобы колонками стал ранг, а значениями - колонка second.
df1 = pd.DataFrame({'pairs': [(551, 566), (515, 551), (489, 551), (523, 551), (566, 794)],
'first': [566, 551, 551, 551, 794],
'second': [551, 515, 489, 523, 566],
'count': [797, 417, 311, 304, 290]})
df2 = pd.DataFrame({'resource_id': list(range(356, 1201))})
df1 = pd.concat([df1, df1.rename(columns={'second': 'first', 'first': 'second'})])
df1['biggest'] = df1.groupby('first')['count'].rank(ascending=False).astype(int)
df = df2.merge(df1[df1.biggest.lt(3)], left_on='resource_id', right_on='first').pivot(index='resource_id', columns='biggest', values='second').reset_index()
print(df)
biggest resource_id 1 2
0 489 551.0 NaN
1 515 551.0 NaN
2 523 551.0 NaN
3 551 566.0 515.0
4 566 551.0 794.0
5 794 566.0 NaN

