У меня есть фрейм данных, который я хочу сгруппировать на основе значения другого столбца в том же фрейме данных.
Например:
Parent_ID и Child 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 (будет иметь только свою запись, ледяная линия №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
Я бы написал рекурсивную функцию для этого.
Сначала создайте словарь {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
@sidman Возможно, ваш df
— это копия слайса. Вы можете попробовать df = df.copy
раньше или df.loc[:, 'Tag'] = df.ID.apply(lambda x: find_parent(x)).str.rstrip(', ')
.
Спасибо ResidentSleeper! Похоже на то. Однако я получаю сообщение об ошибке setcopy:SettingWithCopyWarning: попытка установить значение для копии фрагмента из DataFrame. Попробуйте вместо этого использовать .loc[row_indexer,col_indexer] = value См. предостережения в документации: pandas.pydata.org/pandas-docs/stable/… df['Tag'] = df.ID.apply(lambda x: find_parent(x)).str.rstrip(', ')