#python #pandas #dataframe #hierarchy
#python #pandas #фрейм данных #иерархия
Вопрос:
У меня есть фрейм данных, который я хочу сгруппировать на основе значения другого столбца в том же фрейме данных.
Например:
Parent_ID и дочерний идентификатор связаны и определяют, кто с кем связан в иерархическом дереве.
Фрейм данных выглядит как (ввод из файла CSV)
No Name ID Parent_Id
1 Tom 211 111
2 Galie 209 111
3 Remo 200 101
4 Carmen 212 121
5 Alfred 111 191
6 Marvela 101 111
7 Armin 234 101
8 Boris 454 109
9 Katya 109 323
Я хотел бы сгруппировать этот фрейм данных на основе идентификатора и Parent_ID в приведенной ниже группировке и сгенерировать из этого CSV-файлы на основе родительского элемента верхнего уровня. Т.е. Alfred.csv, Carmen.csv (будет иметь только свою собственную запись, ice line # 4) , Katya.csv с использованием функции to_csv().
Alfred
|_ Galie
_ Tom
_ Marvela
|_ Remo
_ Armin
Carmen
Katya
|_ Boris
И я хочу создать новый столбец в том же фрейме данных, который будет иметь тег, указывающий иерархию. Нравится:
No Name ID Parent_Id Tag
1 Tom 211 111 Alfred
2 Galie 209 111 Alfred
3 Remo 200 101 Marvela, Alfred
4 Carmen 212 121
5 Alfred 111 191
6 Marvela 101 111 Alfred
7 Armin 234 101 Marvela, Alfred
8 Boris 454 109 Katya
9 Katya 109 323
Обратите внимание, что имена могут повторяться, но идентификатор будет уникальным.
Пожалуйста, дайте мне знать, как добиться этого с помощью pandas. Я попробовал groupby(), но кажется немного сложным и не получаю то, что я намереваюсь. Для каждого родительского файла должен быть один файл, а дочерние записи — в родительском файле. Если у дочернего элемента есть другой дочерний элемент (например, marvel), он имеет право иметь свой собственный файл CSV.
И конечный результат будет
Alfred.csv - All records matching Galie, Tom, Marvela
Marvela.csv - All records matching Remo, Armin
Carmen.csv - Only record matching carmen (row)
Katya.csv - all records matching katya, boris
Ответ №1:
Я бы написал рекурсивную функцию для этого.
Сначала создайте словарь {id:name}
, {parent:id}
и рекурсивную функцию.
id_name_dict = dict(zip(df.ID, df.Name))
parent_dict = dict(zip(df.ID, df.Parent_Id))
def find_parent(x):
value = parent_dict.get(x, None)
if value is None:
return ""
else:
# Incase there is a id without name.
if id_name_dict.get(value, None) is None:
return "" find_parent(value)
return str(id_name_dict.get(value)) ", " find_parent(value)
Затем создайте новый столбец с помощью Series.apply
и удалите ', '
с помощью Series.str.strip
df['Tag'] = df.ID.apply(lambda x: find_parent(x)).str.rstrip(', ')
df
No Name ID Parent_Id Tag
0 1 Tom 211 111 Alfred
1 2 Galie 209 111 Alfred
2 3 Remo 200 101 Marvela, Alfred
3 4 Carmen 212 121
4 5 Alfred 111 191
5 6 Marvela 101 111 Alfred
6 7 Armin 234 101 Marvela, Alfred
7 8 Boris 454 109 Katya
8 9 Katya 109 323
Комментарии:
1. Спасибо, ResidentSleeper! Похоже на то. Однако я получаю ошибку с setcopy:SettingWithCopyWarning: значение пытается быть установлено на копии фрагмента из фрейма данных. Попробуйте использовать .loc[row_indexer,col_indexer] = value вместо См. предостережения в документации: pandas.pydata.org/pandas-docs/stable /… df[‘Tag’] = df.ID.apply(лямбда x: find_parent(x)).str.rstrip(‘, ‘)
2. @sidman Может быть, ваш
df
является копией фрагмента. Вы можете попробоватьdf = df.copy
раньше илиdf.loc[:, 'Tag'] = df.ID.apply(lambda x: find_parent(x)).str.rstrip(', ')
.