在pandas DataFrame中添加多个空列

120

如何从列表中向 DataFrame 添加多个空列?

我可以这样做:

df["B"] = None
df["C"] = None
df["D"] = None

但是我做不到:

df[["B", "C", "D"]] = None

KeyError: "['B' 'C' 'D'] not in index"


None和0是不同的,但有些答案假定它们是等价的。此外,赋值为None将会得到一个对象类型(dtype),而赋值为0将会得到一个整数类型(dtype)。 - smci
同时,您不能执行 df[['B','C','D']] = None, None, None[None, None, None]pd.DataFrame([None, None, None]) - smci
8个回答

122

您可以使用df.reindex来添加新列:

In [18]: df = pd.DataFrame(np.random.randint(10, size=(5,1)), columns=['A'])

In [19]: df
Out[19]: 
   A
0  4
1  7
2  0
3  7
4  6

In [20]: df.reindex(columns=list('ABCD'))
Out[20]: 
   A   B   C   D
0  4 NaN NaN NaN
1  7 NaN NaN NaN
2  0 NaN NaN NaN
3  7 NaN NaN NaN
4  6 NaN NaN NaN

reindex会返回一个新的DataFrame,其中列按照它们被列出的顺序出现:

In [31]: df.reindex(columns=list('DCBA'))
Out[31]: 
    D   C   B  A
0 NaN NaN NaN  4
1 NaN NaN NaN  7
2 NaN NaN NaN  0
3 NaN NaN NaN  7
4 NaN NaN NaN  6

reindex 方法也接受 fill_value 参数:

In [22]: df.reindex(columns=list('ABCD'), fill_value=0)
Out[22]: 
   A  B  C  D
0  4  0  0  0
1  7  0  0  0
2  0  0  0  0
3  7  0  0  0
4  6  0  0  0

7
在尝试了一个相当大的数据框(大约2.5k行,80k列)后,该解决方案似乎比被接受的解决方案快几个数量级。顺便问一下,为什么这个特定的命令不接受"inplace=True"参数呢?df = df.reindex(...) 看起来使用了相当多的RAM。 - Marco Spinaci
7
不建议使用 inplace=True。它的作用不是大多数人所认为的那样。在幕后,总是创建一个全新的DataFrame,然后将新DataFrame中的数据复制到原来的DataFrame中。这并没有节省任何内存。因此, inplace=True 是华而不实的,而且名称具有误导性。我没有检查过代码,但我预计 df = df.reindex(...) 至少需要2倍于 df 所需的内存,当使用 reindex 来扩展行数时,内存会更多地被使用。 - unutbu
@unutbu,尽管如此,在迭代容器时它非常有用,例如列表或字典,它可以避免使用索引使代码变得更加混乱... - toto_tico
@unutbu,当我对我的 ~200 列创建代码进行分析时,确实快了很多。您能否简要解释一下为什么重新索引比连接或仅将多个列设置为 numpy 数组要快得多? - Sam

88

我会使用DataFrame来concat

In [23]:
df = pd.DataFrame(columns=['A'])
df

Out[23]:
Empty DataFrame
Columns: [A]
Index: []

In [24]:    
pd.concat([df,pd.DataFrame(columns=list('BCD'))])

Out[24]:
Empty DataFrame
Columns: [A, B, C, D]
Index: []

通过传递一个包含原始 df 和一个新 df 的列表,其中包含您希望添加的列,这将返回一个具有附加列的新 df。


注意:请参阅其他答案和/或评论讨论中关于性能的讨论。在性能关键时,可能更适合使用reindex

47

如果您不想重写旧列的名称,那么可以使用reindex:

df.reindex(columns=[*df.columns.tolist(), 'new_column1', 'new_column2'], fill_value=0)

完整示例

In [1]: df = pd.DataFrame(np.random.randint(10, size=(3,1)), columns=['A'])

In [1]: df
Out[1]: 
   A
0  4
1  7
2  0

In [2]: df.reindex(columns=[*df.columns.tolist(), 'col1', 'col2'], fill_value=0)
Out[2]: 

   A  col1  col2
0  1     0     0
1  2     0     0

如果您已经有一份列名清单,那么:

In [3]: my_cols_list=['col1','col2']

In [4]: df.reindex(columns=[*df.columns.tolist(), *my_cols_list], fill_value=0)
Out[4]: 
   A  col1  col2
0  1     0     0
1  2     0     0

11

备选方案摘要:

columns_add = ['a', 'b', 'c']
  1. for循环:

    for newcol in columns_add:
        df[newcol]= None
    
  2. 字典方法:

    df.assign(**dict([(_,None) for _ in columns_add]))
    
  3. 元组赋值:

    df['a'], df['b'], df['c'] = None, None, None
    

1
df.assign(**dict.fromkeys(columns_add, None)) 应该也可以工作。 - Joe Ferndz

9

为什么不直接使用循环:

for newcol in ['B','C','D']:
    df[newcol]=np.nan

0和None不是相同的值。此外,0会强制转换为整数数据类型,而None则不会。 - smci

7
你可以使用Pandas广播技术:Pandas broadcasting
df = pd.DataFrame({'A': [1, 1, 1]})

df[['B', 'C']] = 2, 3
# df[['B', 'C']] = [2, 3]

结果:

   A  B  C
0  1  2  3
1  1  2  3
2  1  2  3

添加空列:

df[['B', 'C', 'D']] = 3 * [np.nan]

结果:

   A   B   C   D
0  1 NaN NaN NaN
1  1 NaN NaN NaN
2  1 NaN NaN NaN

3

我会使用

df["B"], df["C"], df["D"] = None, None, None


df["B"], df["C"], df["D"] = ["None" for a in range(3)]

1
只是为了增加有趣的方式列表:
columns_add = ['a', 'b', 'c']
df = df.assign(**dict(zip(columns_add, [0] * len(columns_add)))

0和None不是相同的值。另外,0会强制转换为整型数据类型,而None则不会。 - smci
无论如何,您缺少一个尾随的第四个闭括号。 - smci

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接