Pandas: Одновременное присвоение нескольких *новых* столбцов
У меня есть DataFrame df
, содержащий столбец с метками для каждой строки (в дополнение к некоторым соответствующим данным для каждой строки). У меня есть словарь labeldict
, у которого ключи соответствуют возможным меткам, а значения представляют собой 2-кортежи информации, связанной с этой меткой. Мне нужно добавить два новых столбца в мой DataFrame, по одному для каждой части 2-кортежа, соответствующего метке для каждой строки.
Вот мой код:
import pandas as pd
import numpy as np
np.random.seed(1)
n = 10
labels = list('abcdef')
colors = ['red', 'green', 'blue']
sizes = ['small', 'medium', 'large']
labeldict = {c: (np.random.choice(colors), np.random.choice(sizes)) for c in labels}
df = pd.DataFrame({'label': np.random.choice(labels, n),
'somedata': np.random.randn(n)})
Я могу получить желаемый результат, выполнив следующий код:
df['color'], df['size'] = zip(*df['label'].map(labeldict))
print(df)
Но как я могу сделать это, если не хочу вручную вводить названия двух столбцов с левой стороны присваивания? То есть, как я могу создать несколько новых столбцов динамически? Например, если бы у меня были 10-кортежи в labeldict
вместо 2-кортежей, это было бы настоящим утомлением. Вот несколько попыток, которые не работают:
# задать список атрибутов для дальнейшего использования
attrlist = ['color', 'size']
# неработающая идея 1
df[attrlist] = zip(*df['label'].map(labeldict))
# неработающая идея 2
df.loc[:, attrlist] = zip(*df['label'].map(labeldict))
Хотя это работает, это кажется не очень элегантным решением:
for a in attrlist:
df[a] = 0
df[attrlist] = zip(*df['label'].map(labeldict))
Есть ли более хорошие решения?
4 ответ(ов)
Вы можете использовать метод merge
вместо этого:
>>> ld = pd.DataFrame(labeldict).T
>>> ld.columns = ['color', 'size']
>>> ld.index.name = 'label'
>>> df.merge(ld.reset_index(), on='label')
label somedata color size
0 b 1.462108 red medium
1 c -2.060141 green small
2 c 1.133769 green small
3 c 0.042214 green small
4 e -0.322417 red medium
5 e -1.099891 red medium
6 e -0.877858 red medium
7 e 0.582815 red medium
8 f -0.384054 red large
9 d -0.172428 red medium
Таким образом вы сможете объединить ваши данные с помощью общего столбца label
.
Вместо того чтобы использовать labeldict
, вы можете преобразовать эту информацию в DataFrame и затем объединить его с вашим оригинальным DataFrame. Вот пример того, как это можно сделать:
import pandas as pd
import numpy as np
# Пример данных
labels = ['a', 'b', 'a', 'b', 'b', 'd', 'b', 'd', 'e', 'c']
colors = ['red', 'blue', 'green']
sizes = ['small', 'medium', 'large']
# Создание DataFrame с цветами и размерами
labeldf = pd.DataFrame([(np.random.choice(colors), np.random.choice(sizes)) for c in labels], columns=['color', 'size'], index=labels)
# Ваш оригинальный DataFrame
df = pd.DataFrame({
'label': labels,
'somedata': np.random.randn(len(labels))
})
# Объединение DataFrame по метке
result = df.join(labeldf, on='label')
print(result)
В результате вы получите DataFrame, в котором будет объединена информация как из вашего оригинального DataFrame, так и из labeldf
, что позволяет более удобно работать с данными:
label somedata color size
0 a -1.709973 red medium
1 b 0.099109 blue medium
2 a -0.427323 red medium
3 b 0.474995 blue medium
4 b -2.819208 blue medium
5 d -0.998888 red small
6 b 0.713357 blue medium
7 d 0.331989 red small
8 e -0.906240 green large
9 c -0.501916 blue large
Таким образом, использование DataFrame и методов объединения в Pandas делает ваш код более читаемым и упрощает работу с данными.
Если вы хотите добавить несколько столбцов в DataFrame
в рамках цепочки методов, вы можете использовать apply
. Первым шагом необходимо создать функцию, которая преобразует строку, представленную как Series
, в нужный вам формат. Затем можно вызвать apply
, чтобы применить эту функцию к каждой строке.
Пример функции может выглядеть следующим образом:
def append_label_attributes(row: pd.Series, labelmap: dict) -> pd.Series:
result = row.copy()
result['color'] = labelmap[result['label']][0]
result['size'] = labelmap[result['label']][1]
return result
Далее вы можете создать DataFrame
и применить функцию через apply
:
df = (
pd.DataFrame(
{
'label': np.random.choice(labels, n),
'somedata': np.random.randn(n)
}
)
.apply(append_label_attributes, axis='columns', labelmap=labeldict)
)
Таким образом, вы сможете добавить новые столбцы color
и size
к вашему DataFrame
, используя данные из labeldict
.
Это должно сработать:
df[['color', 'size']] = list(df['label'].apply(labeldict))
Таким образом, вы применяете функцию labeldict
к каждому элементу столбца 'label'
и сохраняете результаты в новые столбцы 'color'
и 'size'
вашего DataFrame df
. Убедитесь, что функция labeldict
возвращает результаты в виде списков или кортежей с двумя элементами. Если все настроено правильно, код должен работать корректно.
Преобразование списка словарей в DataFrame pandas
Объединение двух столбцов текста в DataFrame pandas
Импорт нескольких CSV-файлов в pandas и объединение в один DataFrame
Получить список из колонки или строки DataFrame в pandas?
Выбор строки из pandas Series/DataFrame по целочисленному индексу