Найти подходящие подстроки в двух данных

У меня есть два кадра данных, как это:

[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
Другие вопросы по тегам