#python #python-3.x #pandas #list #numpy
#python #python-3.x #pandas #Список #numpy
Вопрос:
Учитывая DataFrame
:
id articleno target
0 1 [607303] 607295
1 1 [607295] 607303
2 2 [243404, 617953] 590448
3 2 [590448, 617953] 243404
для каждой строки вычислите среднее значение встраивания статьи, просматривая каждый элемент в списках в словаре:
embeddings = {"607303": np.array([0.19, 0.25, 0.45])
,"607295": np.array([0.77, 0.76, 0.55])
,"243404": np.array([0.35, 0.44, 0.32])
,"617953": np.array([0.23, 0.78, 0.24])
,"590448": np.array([0.67, 0.12, 0.10])}
Так, например, и для уточнения, для третьей строки (индекс 2) статья вложения для 243404
и 617953
является [0.35, 0.44, 0.32]
и [0.23, 0.78, 0.24]
, соответственно. Среднее встраивание статьи вычисляется как поэлементное сложение всех элементов, деленное на количество статей, так что: ([0.35, 0.44, 0.32] [0.23, 0.78, 0.24])/2=[0.29, 0.61, 0.28]
.
Ожидаемый результат:
id dim1 dim2 dim3 target
0 1 0.19 0.25 0.45 607295
1 1 0.77 0.76 0.55 607303
2 2 0.29 0.61 0.28 590448
3 2 0.45 0.45 0.17 243404
На самом деле my DataFrame
содержит миллионы строк, а списки в articleno
могут содержать гораздо больше элементов. Из-за этого итерация по строкам может быть слишком медленной, и может потребоваться более эффективное решение (возможно, векторизованное).
Более того, количество измерений (размер встраивания) известно заранее, но составляет пару сотен, поэтому количество столбцов; dim1
, dim2
, dim3
, ...
dimN
должно быть динамическим, основанным на размерах встраивания ( N
).
Комментарии:
1. Это делает ваш предыдущий вопрос действительно проблемой XY . Вы можете решить проблему из исходных данных намного проще.
2. @QuangHoang Не могли бы вы немного расширить? Я открыт для идей о том, как построить предварительную обработку данных более эффективным способом.
Ответ №1:
В предыдущем вопросе вы потратили дополнительные мили на разделение элементов в articleno
списке, а затем удалили target
из articleno
списка. Теперь, если вы хотите получить доступ к элементам внутри articleno
списка, вам нужно снова пройти дополнительные мили, чтобы разделить их.
Чтобы проиллюстрировать, что я имею в виду, вот подход, который генерирует оба вывода из двух вопросов, добавляя при этом минимальный дополнительный код:
# construct the embeddings dataframe:
embedding_df = pd.DataFrame(embeddings).T.add_prefix('dim')
# aggregation dictionary
agg_dict = {'countrycode':'first','articleno':list}
# taking mean over embedddings
for i in embedding_df.columns: agg_dict[i] = 'mean'
new_df = df.explode('articleno')
(new_df.join(new_df['articleno'].rename('target'))
.query('articleno != target')
.merge(embedding_df, left_on='articleno', right_index=True) # this line is extra from the previous question
.groupby(['id','target'], as_index=False)
.agg(agg_dict)
)
Вывод:
id target countrycode articleno dim0 dim1 dim2
0 2 590448 US [617953, 617953] 0.23 0.78 0.24
1 2 617953 US [590448, 590448] 0.67 0.12 0.10
Теперь, если вам не нужен articleno
столбец в конечном выводе, вы можете даже упростить свой код, сократив объем памяти и время выполнения следующим образом:
total_embeddings = g[embedding_df.columns].sum()
article_counts = g['id'].transform('size')
new_df[embedding_df.columns] = (total_embeddings.sub(new_df[embedding_df.columns])
.div(article_counts-1, axis=0)
)
и вы получили бы тот же результат.
Комментарии:
1. Спасибо вам за подробный ответ. Еще одна деталь, когда вы создаете
agg_dict
withmean
, я также хотел бы изменить его наabsmax
— чтобы получить не только средние вложения, но и максимальные вложения (но максимум в абсолютных значениях) Конечно, это не работает (посколькуabsmax
не существует). Я пытался использовать функцию вместо строки, например ,lambda x: x.abs().idxmax()
, но это ужасно медленно и работает не так, как ожидалось. У вас есть какие-нибудь предложения?