Как добавить несколько столбцов в фрейм данных pandas за одно задание?

122

Я новичок в пандах и пытаюсь понять, как одновременно добавить несколько столбцов в панды. Любая помощь здесь приветствуется. В идеале я хотел бы сделать это за один шаг, а не за несколько повторяющихся шагов ...

import pandas as pd

df = {'col_1': [0, 1, 2, 3],
        'col_2': [4, 5, 6, 7]}
df = pd.DataFrame(df)

df[[ 'column_new_1', 'column_new_2','column_new_3']] = [np.nan, 'dogs',3]  #thought this would work here...
бегущие птицы
источник
Вам необходимо указать, какая у вас ошибка. Когда я пробую это на pandas 1.0, я получаюKeyError: "None of [Index(['column_new_1', 'column_new_2', 'column_new_3'], dtype='object')] are in the [columns]"
smci

Ответы:

187

Я ожидал, что ваш синтаксис тоже будет работать. Проблема возникает из-за того, что при создании новых столбцов с синтаксисом списка столбцов ( df[[new1, new2]] = ...) pandas требует, чтобы правая сторона была DataFrame (обратите внимание, что на самом деле не имеет значения, имеют ли столбцы DataFrame те же имена, что и столбцы вы создаете).

Ваш синтаксис отлично подходит для присвоения скалярных значений существующим столбцам, и pandas также с радостью назначает скалярные значения новому столбцу, используя синтаксис одного столбца ( df[new1] = ...). Таким образом, решение состоит в том, чтобы либо преобразовать это в несколько назначений с одним столбцом, либо создать подходящий DataFrame для правой стороны.

Вот несколько подходов, которые будут работать:

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'col_1': [0, 1, 2, 3],
    'col_2': [4, 5, 6, 7]
})

Тогда одно из следующего:

1) Три присваивания в одном, используя распаковку списка:

df['column_new_1'], df['column_new_2'], df['column_new_3'] = [np.nan, 'dogs', 3]

2) DataFrameудобно расширяет одну строку в соответствии с индексом, поэтому вы можете сделать это:

df[['column_new_1', 'column_new_2', 'column_new_3']] = pd.DataFrame([[np.nan, 'dogs', 3]], index=df.index)

3) Создайте временный фрейм данных с новыми столбцами, а затем объедините его с исходным фреймом данных позже:

df = pd.concat(
    [
        df,
        pd.DataFrame(
            [[np.nan, 'dogs', 3]], 
            index=df.index, 
            columns=['column_new_1', 'column_new_2', 'column_new_3']
        )
    ], axis=1
)

4) Аналогично предыдущему, но с использованием joinвместо concat(может быть менее эффективным):

df = df.join(pd.DataFrame(
    [[np.nan, 'dogs', 3]], 
    index=df.index, 
    columns=['column_new_1', 'column_new_2', 'column_new_3']
))

5) Использование dict - более «естественный» способ создания нового фрейма данных, чем два предыдущих, но новые столбцы будут отсортированы в алфавитном порядке (по крайней мере, до Python 3.6 или 3.7 ):

df = df.join(pd.DataFrame(
    {
        'column_new_1': np.nan,
        'column_new_2': 'dogs',
        'column_new_3': 3
    }, index=df.index
))

6) Используйте .assign()с несколькими аргументами столбца.

Мне очень нравится этот вариант ответа @ zero, но, как и предыдущий, новые столбцы всегда будут отсортированы в алфавитном порядке, по крайней мере, в ранних версиях Python:

df = df.assign(column_new_1=np.nan, column_new_2='dogs', column_new_3=3)

7) Это интересно (на основе https://stackoverflow.com/a/44951376/3830997 ), но я не знаю, когда это того стоит:

new_cols = ['column_new_1', 'column_new_2', 'column_new_3']
new_vals = [np.nan, 'dogs', 3]
df = df.reindex(columns=df.columns.tolist() + new_cols)   # add empty cols
df[new_cols] = new_vals  # multi-column assignment works for existing cols

8) В конце концов, сложно пройти три отдельных задания:

df['column_new_1'] = np.nan
df['column_new_2'] = 'dogs'
df['column_new_3'] = 3

Примечание: многие из этих параметров уже были рассмотрены в других ответах: добавить несколько столбцов в DataFrame и установить их равными существующему столбцу , можно ли добавить сразу несколько столбцов в DataFrame pandas? , Добавить несколько пустых столбцов в pandas DataFrame

Маттиас Фрипп
источник
Не стал бы подход # 7 ( .reindex) изменить индекс фрейма данных? Зачем кому-то без нужды изменять индекс при добавлении столбцов, если это не явная цель ...
Acumenus
1
.reindex()используется с columnsаргументом, поэтому он изменяет только "индекс" столбца (имена). Это не меняет индекс строки.
Маттиас Фрипп,
для некоторых подходов вы можете использовать OrderedDict: например,df.join(pd.DataFrame( OrderedDict([('column_new_2', 'dogs'),('column_new_1', np.nan),('column_new_3', 3)]), index=df.index ))
hashmuke
@hashmuke Это имеет смысл для ранних версий Python. Это может особенно понравиться людям, использующим словари для нескольких вещей в Pandas, например, df = pd.DataFrame({'before': [1, 2, 3], 'after': [4, 5, 6]})vs.df = pd.DataFrame(OrderedDict([('before', [1, 2, 3]), ('after', [4, 5, 6])])
Маттиас Фрипп
2
Если вы используете опцию с join, убедитесь, что у вас нет дубликатов в вашем индексе (или используйте reset_indexпервый). Может сэкономить несколько часов на отладке.
Гвидо
40

Вы можете использовать assignс диктовкой имен столбцов и значений.

In [1069]: df.assign(**{'col_new_1': np.nan, 'col2_new_2': 'dogs', 'col3_new_3': 3})
Out[1069]:
   col_1  col_2 col2_new_2  col3_new_3  col_new_1
0      0      4       dogs           3        NaN
1      1      5       dogs           3        NaN
2      2      6       dogs           3        NaN
3      3      7       dogs           3        NaN
Нуль
источник
Есть ли способ сделать то же самое, сохраняя определенный порядок столбцов?
user48956
1
Вы можете поддерживать определенный порядок в более ранних версиях Python, вызывая assign несколько раз: df.assign(**{'col_new_1': np.nan}).assign(**{'col2_new_2': 'dogs'}).assign(**{'col3_new_3': 3})
skasch
Если имена столбцов содержат только строки , которые являются именами правовых переменными: df.assign(col_new_1=np.nan, col2_new_2='dogs', col3_new_3=3). Это поддерживает порядок.
Тобиас Бергквист
9

С использованием concat :

In [128]: df
Out[128]: 
   col_1  col_2
0      0      4
1      1      5
2      2      6
3      3      7

In [129]: pd.concat([df, pd.DataFrame(columns = [ 'column_new_1', 'column_new_2','column_new_3'])])
Out[129]: 
   col_1  col_2 column_new_1 column_new_2 column_new_3
0    0.0    4.0          NaN          NaN          NaN
1    1.0    5.0          NaN          NaN          NaN
2    2.0    6.0          NaN          NaN          NaN
3    3.0    7.0          NaN          NaN          NaN

Не очень уверен, что ты хочешь делать [np.nan, 'dogs',3]. Может теперь выставить их как значения по умолчанию?

In [142]: df1 = pd.concat([df, pd.DataFrame(columns = [ 'column_new_1', 'column_new_2','column_new_3'])])
In [143]: df1[[ 'column_new_1', 'column_new_2','column_new_3']] = [np.nan, 'dogs', 3]

In [144]: df1
Out[144]: 
   col_1  col_2  column_new_1 column_new_2  column_new_3
0    0.0    4.0           NaN         dogs             3
1    1.0    5.0           NaN         dogs             3
2    2.0    6.0           NaN         dogs             3
3    3.0    7.0           NaN         dogs             3
Нехал Дж. Вани
источник
если был способ выполнить вторую часть за один шаг - да, например, постоянные значения в столбцах.
runningbirds
3

использование понимания списков pd.DataFrameиpd.concat

pd.concat(
    [
        df,
        pd.DataFrame(
            [[np.nan, 'dogs', 3] for _ in range(df.shape[0])],
            df.index, ['column_new_1', 'column_new_2','column_new_3']
        )
    ], axis=1)

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

PiRSquared
источник
3

если добавить много пропущенных столбцов (a, b, c, ....) с тем же значением, здесь 0, я сделал следующее:

    new_cols = ["a", "b", "c" ] 
    df[new_cols] = pd.DataFrame([[0] * len(new_cols)], index=df.index)

Он основан на втором варианте принятого ответа.

А. Рабус
источник
0

Просто хочу указать на этот вариант2 в ответе @Matthias Fripp

(2) Я бы не ожидал, что DataFrame будет работать таким образом, но это действительно так.

df [['column_new_1', 'column_new_2', 'column_new_3']] = pd.DataFrame ([[np.nan, 'dogs', 3]], index = df.index)

уже задокументирован в собственной документации pandas http://pandas.pydata.org/pandas-docs/stable/indexing.html#basics

Вы можете передать список столбцов в [], чтобы выбирать столбцы в указанном порядке. Если столбец не содержится в DataFrame, возникает исключение. Таким же образом можно установить несколько столбцов. Вы можете найти это полезным для применения преобразования ( на месте ) к подмножеству столбцов.

полумесяц
источник
Я думаю, что это довольно стандартно для назначения нескольких столбцов. Что меня удивило, так это то, что pd.DataFrame([[np.nan, 'dogs', 3]], index=df.index)реплицирует одну строку, которая дается для создания целого фрейма данных той же длины, что и индекс.
Маттиас Фрипп
0

Если вы просто хотите добавить пустые новые столбцы, переиндекс сделает работу

df
   col_1  col_2
0      0      4
1      1      5
2      2      6
3      3      7

df.reindex(list(df)+['column_new_1', 'column_new_2','column_new_3'], axis=1)
   col_1  col_2  column_new_1  column_new_2  column_new_3
0      0      4           NaN           NaN           NaN
1      1      5           NaN           NaN           NaN
2      2      6           NaN           NaN           NaN
3      3      7           NaN           NaN           NaN

полный пример кода

import numpy as np
import pandas as pd

df = {'col_1': [0, 1, 2, 3],
        'col_2': [4, 5, 6, 7]}
df = pd.DataFrame(df)
print('df',df, sep='\n')
print()
df=df.reindex(list(df)+['column_new_1', 'column_new_2','column_new_3'], axis=1)
print('''df.reindex(list(df)+['column_new_1', 'column_new_2','column_new_3'], axis=1)''',df, sep='\n')

в противном случае выберите нулевой ответ с помощью assign

Маркус Дучке
источник
0

Мне неудобно использовать "Индекс" и т. Д. ... может появиться как показано ниже

df.columns
Index(['A123', 'B123'], dtype='object')

df=pd.concat([df,pd.DataFrame(columns=list('CDE'))])

df.rename(columns={
    'C':'C123',
    'D':'D123',
    'E':'E123'
},inplace=True)


df.columns
Index(['A123', 'B123', 'C123', 'D123', 'E123'], dtype='object')
Alex
источник