#python #pandas #performance #networkx #subgraph
#python #pandas #Производительность #networkx #подграф
Вопрос:
Из списка из ~ 500 тысяч строк, состоящего из пар элементов, я пытаюсь создать файл, целью которого является выделение для каждого элемента идентификатора, связанного с группой, к которой они принадлежат. Далее следуют пояснения.
И мне понадобится некоторая помощь, чтобы получить результат разумным и эффективным способом (то есть pythonic)
==============
что я хочу сделать
Преобразуйте входной файл df0 в желаемый результат df2
Например, начальный файл будет выглядеть следующим образом (но с 500 тысячами записей), где отношение от item1 к item2 определяется структурой фрейма данных.
df0: ввод
df0 = pd.DataFrame({
"item 1": ['Q', 'R', 'B', 'A'],
"item 2": ['R', 'P', 'A', 'C']
})
Он читается следующим образом: элемент Q связан с элементом R, а элемент R связан с элементом P, следовательно, элемент Q связан с элементом P (то же самое с С A, B и C). В этом случае транзитивность отношений приводит к созданию двух групп элементов.
- Каждый элемент принадлежит только к 1 группе.
- Ожидается, что в реальном файле примера группы могут содержать до 11 элементов.
- алфавитный порядок не играет роли
Благодаря другим вкладам в stackoverflow мне удалось сгруппировать все транзитивные элементы в отдельные наборы и присвоить им единый номер группы (или ID). Это означает, что я получаю фрейм данных, который выглядит следующим образом:
df1 = pd.DataFrame({
"items": [{'Q', 'R', 'P'}, {'B', 'A', 'C'} ],
"group": [1, 2]
})
Приведенный выше результат теперь должен быть преобразован для поддержки дальнейшей последующей обработки данных, и желаемый результат должен выглядеть следующим образом:
df2: желаемый результат
df2 = pd.DataFrame({
"items": ['Q', 'R', 'P', 'B', 'A', 'C' ],
"group": [1, 1, 1, 2, 2, 2 ]
})
==============
Что мне удалось до сих пор
шаг 1: преобразуйте df1.item в серию отдельных элементов
d = df1.item
e = list(sorted(set(chain.from_iterable(d))))
df2 = pd.DataFrame({'item':e})
шаг 2: ‘vlookup’ df2.items возвращается в df1.group через df1.items
df2['group'] = ''
n = 0
for row in df2.items :
m = 0
for row in df1.items :
if df2['items'][n] in df1['items'][m]:
df2['group'][n] = df1['group'][m]
m = m 1
n = n 1
==============
Это работает для небольших таблиц, но не работает на больших фреймах данных.
Сейчас я ищу помощь относительно :
- либо лучший код для шага 2 для улучшения df2 (предпочтительно)
- или лучший способ перепрыгнуть через шаг 2 и получить df2 прямо из df1
Заранее благодарю вас за ваше время и обратную связь!
Комментарии:
1. 1)
R
Связано сB
? 2) Почему вы хотите использовать фреймы данных?2. 1) согласно df0, R не связан с B. Иначе у нас была бы только одна группа. 2) У меня нет ограничений не использовать фреймы данных, я открыт для альтернатив.
Ответ №1:
IIUC, вы могли бы попробовать заглянуть в networkx
библиотеку.
Вы можете создать непрямый сетевой график непосредственно из своего pandas.DataFrame
и использовать connected_component_subgraphs
метод для извлечения подгрупп:
import networkx as nx
df0 = pd.DataFrame({'item 1': {0: 'Q', 1: 'R', 2: 'B', 3: 'A'},
'item 2': {0: 'R', 1: 'P', 2: 'A', 3: 'C'}})
g = nx.convert_matrix.from_pandas_edgelist(df0, source='item 1', target='item 2')
Используйте понимание списка для создания данных для вашего нового DataFrame
subgroups = [(n, i 1) for i, sg in enumerate(nx.connected_component_subgraphs(g)) for n in sg.nodes]
df2 = pd.DataFrame(subgroups, columns=['items', 'subgroup'])
print(df2)
items subgroup
0 P 1
1 R 1
2 Q 1
3 C 2
4 A 2
5 B 2
Комментарии:
1. потрясающе Я только что протестировал в Jupyter файл размером ~ 400 тыс. строк, и он отлично сработал! большое вам спасибо!
2. @ionah рад помочь 🙂