如何在一次分配中向熊猫数据框添加多列?


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

Answers:


185

我希望您的语法也能正常工作。出现问题是因为当您使用column-list语法(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并将它们设置为等于现有列是否可以一次将多个列添加到pandas DataFrame?向pandas DataFrame添加多个空列


方法7(.reindex)是否会更改数据框的索引?为什么有人想要在添加列时不必要地更改索引,除非这是一个明确的目标……
Acumenus

1
.reindex()columns参数一起使用,因此它仅更改列“索引”(名称)。它不会改变行索引。
Matthias Fripp

对于某些方法,您可以使用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的早期版本是有意义的。它尤其吸引使用字典对大熊猫多东西的人,例如,df = pd.DataFrame({'before': [1, 2, 3], 'after': [4, 5, 6]})df = pd.DataFrame(OrderedDict([('before', [1, 2, 3]), ('after', [4, 5, 6])])
马蒂亚斯弗里普

2
如果您将选项与一起使用join,请确保索引中没有重复项(或使用reset_index第一个)。可能会节省您几个小时的调试时间。
Guido

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 '18

1
您可以通过多次调用df.assign(**{'col_new_1': np.nan}).assign(**{'col2_new_2': 'dogs'}).assign(**{'col3_new_3': 3})
Assign

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)

在此处输入图片说明


3

如果添加许多具有相同值的缺失列(a,b,c,....),这里为0,我这样做:

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

它基于已接受答案的第二个变体。


0

只想指出@Matthias Fripp的答案中的option2

(2)我不一定希望DataFrame可以这种方式工作,但确实可以

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

已记录在熊猫自己的文档中 http://pandas.pydata.org/pandas-docs/stable/indexing.html#basics

您可以将列列表传递给[],以按此顺序选择列。如果DataFrame中不包含任何列,则将引发异常。 也可以以此方式设置多列。 您可能会发现这对于将转换(就地)应用于列的子集很有用。


我认为这是多列分配的相当标准。让我感到惊讶的部分是,它pd.DataFrame([[np.nan, 'dogs', 3]], index=df.index)复制了一行以创建与索引长度相同的整个数据框。
马提亚斯·弗里普

0

如果您只想添加空的新列,则reindex将完成此工作

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')

否则去分配答案


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')
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.