У меня есть список (list_to_match = ['a','b','c','d']) и фрейм данных, как показано ниже:
Моя цель состояла бы в том, чтобы отфильтровать строки с наибольшим количеством совпадений со списком в соответствующей позиции (например, позиция 1 в списке должна соответствовать столбцу 1, позиция 2 столбцу 2 и т. д.). В этом конкретном случае, исключая строку 100, строки 5 и 6 будут выбраны, поскольку они соответствуют «a», «b» и «c», но если строка 100 должна быть включена, строка 100 и все остальные строки, соответствующие всем элементам был бы избранным. Также список может измениться по длине, например. list_to_match = ['a','b'].
Спасибо за вашу помощь!
Я подумал, может быть, цикл, в котором он сначала фильтрует фрейм данных для первого столбца, если он равен «a», а затем, если длина результирующего нарезанного фрейма данных отличается от «0», он переходит к следующему и пытается фильтровать ( уже отфильтровано с помощью «a») кадра данных с помощью «b», и если длина этой новой отфильтрованной базы данных выше «0», она идет дальше и т. д., и цикл прерывается всякий раз, когда длина отфильтрованного кадра данных равна нулю, выбирая предыдущий уровень как хороший
Я думаю, что в этом случае вам нужно только решение с cummin или cumprod, такое как решение mozway или мое обновленное решение @DarioBani.
Я хотел бы использовать:
list_to_match = ['a','b','c','d']
# compute a mask of identical values
mask = df.iloc[:, :len(list_to_match)].eq(list_to_match)
# ensure we match values in order
mask2 = mask.cummin(axis=1).sum(axis=1)
# get the rows with max matches
out = df[mask2.eq(mask2.max())]
# or
# out = df.loc[mask2.nlargest(1, keep='all').index]
print(out)
Вывод (игнорируя входную строку 100):
One Two Three Four
Index
5 a b c g
6 a b c None
Я вижу это как возможное решение, проблема в том, что список имеет переменную длину, например. ['a','b'], в этом случае я считаю, что этот ломается.
Я также изменил основной пост, извиняюсь за поправку
@DarioBani прост в обращении, смотрите обновление
Я полагаю, что мы почти закончили, листья mask2 создают маску, в которой желательные строки на выходе - это строки с наибольшим значением, но затем "out" показывает не фильтрацию df для этих строк, а для других... действительно странно
@ Дарио, насколько я понимаю, вы хотели исключить строку 100, поскольку она содержала все совпадения, если это неверно, упростите мое решение с помощью: out = df[mask2.eq(mask2.max())] или out = df.loc[mask2.nlargest(1, keep='all').index]
Я определенно злоупотребляю вашим терпением, но есть ли способ, которым я могу нарезать df так, как вы это сделали, добавьте, например, +100 ко всем значениям одного столбца (например, «Шесть») нарезанного фрейма данных, и это влияет на исходный df?
@ Дарио не уверен, что понял, что вы имеете в виду, вы хотите выполнить логическое индексирование? Может стоит открыть дополнительный вопрос?
Вот мой подход. Описания комментируются ниже.
import pandas as pd
import numpy as np
from scipy.spatial.distance import cosine
data = {'One': ['a', 'a', 'a', 'a'],
'Two': ['b', 'b', 'b', 'b'],
'Three': ['c', 'c', 'y', 'c'],
'Four': ['g', 'g', 'z', 'd']}
dataframe_ = pd.DataFrame(data)
#encoding Letters into numerical values so we can compute the cosine similarities
dataframe_[:] = dataframe_.to_numpy().astype('<U1').view(np.uint32)-64
#Our input data which we are going to compare with other rows
input_data = np.array(['a', 'b', 'c', 'd'])
#encode input data into numerical values
input_data = input_data.astype('<U1').view(np.uint32)-64
#compute cosine similarity for each row
dataframe_out = dataframe_.apply(lambda row: 1 - cosine(row, input_data), axis=1)
print(dataframe_out)
Выход:
0 0.999343
1 0.999343
2 0.973916
3 1.000000
Фильтрация строк на основе сходства их косинусов:
df_filtered = dataframe_out[dataframe_out.iloc[:, [0]] > 0.99]
print(df_filtered)
0 0.999343
1 0.999343
2 NaN
3 1.000000
Отсюда вы можете легко найти строки со значениями, отличными от NaN, по их индексам.
Так вам нужны строки фильтра, количество совпадений которых равно максимальному количеству совпадений среди всех строк?