Найти подходящие подстроки в двух данных
У меня есть два кадра данных, как это:
[in]print(training_df.head(n=10))
[out]
product_id
transaction_id
0000001 [P06, P09]
0000002 [P01, P05, P06, P09]
0000003 [P01, P06]
0000004 [P01, P09]
0000005 [P06, P09]
0000006 [P02, P09]
0000007 [P01, P06, P09, P10]
0000008 [P03, P05]
0000009 [P03, P09]
0000010 [P03, P05, P06, P09]
[in]print(testing_df.head(n=10))
[out]
product_id
transaction_id
001 [P01]
002 [P01, P02]
003 [P01, P02, P09]
004 [P01, P03]
005 [P01, P03, P05]
006 [P01, P03, P07]
007 [P01, P03, P08]
008 [P01, P04]
009 [P01, P04, P05]
010 [P01, P04, P08]
Каждая строка в testing_df является возможной "подстрокой" строки в training_df. Я хотел бы найти все совпадения и вернуть возможные списки training_df для каждого списка в testing_df. Было бы полезно, если бы я мог вернуть словарь, ключами которого являются транзакции_id из testing_df, а значения - все возможные "совпадения" в training_df. (Каждый список в training_df должен быть на одно значение длиннее соответствующего списка в test_df).
Я старался:
# Find the substrings that match
matches = []
for string in training_df:
results = []
for substring in testing_df:
if substring in string:
results.append(substring)
if results:
matches.append(results)
Однако это не работает, он только возвращает имя столбца 'product_id'.
Я также попробовал:
# Initialize a list to store the matches between incomplete testing_df and training_df
matches = {}
# Compare the "incomplete" testing lists to the training set
for line in testing_df.product_id:
for line in training_df.product_id:
if line in testing_df.product_id in line in training_df.product_id:
matches[line] = training_df[training_df.product_id.str.contains(line)]
Однако это выдает ошибку TypeError: unhashable type: 'list'
1 ответ
Я думаю, что проблема в скобках. Проблема в том, что in
проверяет, есть ли элемент в списке, а не является ли один список подмножеством другого. Вы можете преобразовать два списка в наборы, а затем проверить, являются ли они подмножествами друг друга. Вы также можете использовать расширенную индексацию, чтобы сохранить transaction_id
:
training_df = pd.DataFrame([
['0000001', ['P06', 'P09']],
['0000002', ['P01', 'P05', 'P06', 'P09']],
['0000003', ['P01', 'P06']],
['0000004', ['P01', 'P09']],
['0000005', ['P06', 'P09']],
['0000006', ['P02', 'P09']],
['0000007', ['P01', 'P06', 'P09', 'P10']],
['0000008', ['P03', 'P05']],
['0000009', ['P03', 'P09']],
['0000010', ['P03', 'P05', 'P06', 'P09']],
], columns=['transaction_id', 'product_id'])
testing_df = pd.DataFrame([
['001', ['P01']],
['002', ['P01', 'P02']],
['003', ['P01', 'P02', 'P09']],
['004', ['P01', 'P03']],
['005', ['P01', 'P03', 'P05']],
['006', ['P01', 'P03', 'P07']],
['007', ['P01', 'P03', 'P08']],
['008', ['P01', 'P04']],
['009', ['P01', 'P04', 'P05']],
['010', ['P01', 'P04', 'P08']],
], columns=['transaction_id', 'product_id'])
matches = {}
for testing_id in testing_df.product_id:
testing_id_set = set(testing_id)
contains_id = training_df.product_id.apply(lambda id: testing_id_set.issubset(set(id)))
matches[str(testing_id)] = contains_id