Многоуровневые значения поиска в фрейме данных с вложенными данными

#python #pandas

Вопрос:

У меня есть следующий фрейм данных:

введите описание изображения здесь

Различные красные цвета (строка 1-3) сгруппированы в группу «Темно — красный». Они входят в «Красную» группу (7-8) и «Темную» группу (14-16). «Красная» группа (7-8) ссылается на дополнительную группу: «Цвет» (11-13).


Цель состоит в том, чтобы получить список всех групп, на которые ссылаются, для каждого «Значения».

Пример:

Ввод: "Scarlet Red"

Ожидаемый Результат: ['Scarlet Red', 'Dark Red', 'Red', 'Dark', 'Color']


Примеры данных:

 import pandas as pd
d = {'ID': {0: 'P1',  1: 'C1',  2: 'C2',  3: 'P2',  4: 'C3',  5: 'C4',  6: 'L1',  7: 'P1',  8: 'L2',  9: 'P2',  10: 'LL1',  11: 'L1',  12: 'L2',  13: 'D1',  14: 'P1',  15: 'P2'}, 'Values': {0: 'Dark Red',  1: 'Scarlet Red',  2: 'Cherry Red',  3: 'Dark Blue',  4: 'Steel Blue',  5: 'Coral Blue',  6: 'Red',  7: 'Dark Red',  8: 'Blue',  9: 'Dark Blue',  10: 'Color',  11: 'Red',  12: 'Blue',  13: 'Dark',  14: 'Dark Red',  15: 'Dark Blue'}, 'Type': {0: 'Preferred',  1: 'Name',  2: 'Name',  3: 'Preferred',  4: 'Name',  5: 'Name',  6: 'Preferred',  7: 'Name',  8: 'Preferred',  9: 'Name',  10: 'Preferred',  11: 'Name',  12: 'Name',  13: 'Preferred',  14: 'Name',  15: 'Name'}, 'Group': {0: 1,  1: 1,  2: 1,  3: 2,  4: 2,  5: 2,  6: 3,  7: 3,  8: 4,  9: 4,  10: 5,  11: 5,  12: 5,  13: 6,  14: 6,  15: 6}, 'Level': {0: 0,  1: 0,  2: 0,  3: 0,  4: 0,  5: 0,  6: 1,  7: 1,  8: 1,  9: 1,  10: 2,  11: 2,  12: 2,  13: 1,  14: 1,  15: 1}}
df = pd.DataFrame(d)
 

Нынешний подход:

 # get the preferred names
df_pref =  df[df['Type'].eq('Preferred')][['Values', 'Group']].rename(columns={'Values': 'Preferred'})
df_merge = df.merge(df_pref, on=['Group'], how='left')

def find_higher_levels(search):
    # search = 'Scarlet Red'
    lst = [search]
    previous_search = None
    while search != previous_search:
        previous_search = search
        search = df_merge[df_merge['Values'].eq(search)]['Preferred'].iloc[-1]
        lst.append(search)
    return lst

find_higher_levels('Scarlet Red')
# Out[85]: ['Scarlet Red', 'Dark Red', 'Dark', 'Dark']
 

Примечание: Даже если функция будет работать так, как ожидалось, мне придется сопоставить ее с каждым значением в разделе «Значения». Мой вопрос в том, есть ли более разумный подход к этому.

Комментарии:

1. Есть ли причина, по которой все эти данные находятся во фрейме данных? Обычно фрейм данных должен быть довольно семантически плоским. Если он не является семантически плоским, работать с вложенностью непросто. Похоже, у вас здесь вложенные данные.

2. @KyleParsons, хорошая мысль, я открыт для предложений. Причина в том, что существует несколько похожих таблиц (но не таких глубоко вложенных, как эта), поэтому я хотел иметь аналогичный формат, но это не является жестким требованием.

3. @KyleParsons нашел решение, которое работает для фрейма данных. См.Ответ ниже.

Ответ №1:

Я решил эту проблему с networx помощью библиотеки:

Примеры данных:

 import pandas as pd
df = pd.DataFrame({'ID': {0: 'Dark Red',  1: 'Scarlet Red',  2: 'Cherry Red',  3: 'Dark Blue',  4: 'Steel Blue',  5: 'Coral Blue',  6: 'Red',  7: 'Dark Red',  8: 'Blue',  9: 'Dark Blue',  10: 'Color',  11: 'Red',  12: 'Blue',  13: 'Dark',  14: 'Dark Red',  15: 'Dark Blue'}, 'Start': {0: 'P1',  1: 'C1',  2: 'C2',  3: 'P2',  4: 'C3',  5: 'C4',  6: 'L1',  7: 'P1',  8: 'L2',  9: 'P2',  10: 'LL1',  11: 'L1',  12: 'L2',  13: 'D1',  14: 'P1',  15: 'P2'}, 'End': {0: 'P1',  1: 'P1',  2: 'P1',  3: 'P2',  4: 'P2',  5: 'P2',  6: 'L1',  7: 'L1',  8: 'L2',  9: 'L2',  10: 'LL1',  11: 'LL1',  12: 'LL1',  13: 'D1',  14: 'D1',  15: 'D1'}})
dct = df.set_index('Start')['ID'].to_dict() # translate nodes to their names later on
 

Код:

 import networkx as nx
G = nx.Graph()
G = nx.from_pandas_edgelist(df, 'Start', 'End', create_using=nx.DiGraph())
T = nx.dfs_tree(G, source='C1').reverse()
print([dct.get(x) for x in T])
# Out: ['Scarlet Red', 'Dark Red', 'Red', 'Color', 'Dark']