【问题标题】:Add multiple empty columns to pandas DataFrame向 pandas DataFrame 添加多个空列
【发布时间】:2015-09-04 18:13:45
【问题描述】:

如何将多个空列添加到列表中的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 将给出 int 的 dtype。
  • 你也不能这样做df[['B','C','D']] = None, None, None[None, None, None]pd.DataFrame([None, None, None])

标签: python pandas


【解决方案1】:

您可以使用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

【讨论】:

    【解决方案2】:

    替代解决方案总结:

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

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

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

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

    【讨论】:

    • df.assign(**dict.fromkeys(columns_add, None)) 也应该可以工作
    【解决方案3】:

    我会用

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

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

    【讨论】:

      【解决方案4】:

      为什么不直接使用循环:

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

      【讨论】:

      • 0 与 None 的值不同。此外,它会强制 dtype 为整数,而 None 不会。
      【解决方案5】:

      只是添加到有趣的方式列表中:

      columns_add = ['a', 'b', 'c']
      df = df.assign(**dict(zip(columns_add, [0] * len(columns_add)))
      

      【讨论】:

      • 0 与 None 的值不同。此外,它会强制 dtype 为整数,而 None 不会。
      • 无论如何你都缺少一个尾随的第四个右括号。
      【解决方案6】:

      我会 concat 使用 DataFrame:

      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。


      警告:请参阅其他 answers 和/或评论讨论中的性能讨论。 reindex 在性能至关重要的情况下可能更可取。

      【讨论】:

      • 谢谢,我可能遗漏了一些东西,但我添加了pd.concat([df,pd.DataFrame(columns=list('BCD'))])——它什么也没做。难道是因为我使用df = pd.read_csv而不是df = pd.DataFrame
      • 你需要分配concat的结果所以df=pd.concat([df,pd.DataFrame(columns=list('BCD'))])
      • 这不应该发生,您可以使用花哨的索引来更改列顺序:df.ix[:, col_list],或者只需选择它们并将它们分配回原始 df:df = df[col_list]
      • 这不再起作用(使用 pandas 0.19.1)。串联导致TypeError: data type not understood
      • @thenaturalist 抱歉,这仍然适用于我在 pandas 0.19.1 你需要发布我可以运行的完整代码
      【解决方案7】:

      如果你不想重写旧列的名称,那么你可以使用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
      

      【讨论】:

      • 谢谢。您能告诉我*reindex 输入中的作用吗?
      • 它将列表解包为位置参数,它是a Python operator
      • 不错的解决方案。顺便说一句,没有必要打电话给tolist()
      【解决方案8】:

      您可以使用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
      

      【讨论】:

      • 在尝试了一个中等大小的数据框(约 2.5k 行,80k 列)之后,这个解决方案似乎比接受的解决方案快几个数量级。顺便说一句,这个特定命令是有原因的不接受“inplace=True”参数? df = df.reindex(...) 似乎消耗了相当多的 RAM。
      • @MarcoSpinaci:我建议不要使用inplace=True。它不像大多数人认为的那样做。在底层,总是会创建一个全新的 DataFrame,然后将来自新 DataFrame 的数据复制到原始 DataFrame 中。这不会节省任何内存。所以inplace=True 是装点门面,没有实质内容,而且名称有误导性。我没有检查代码,但我预计df = df.reindex(...) 需要至少 2 倍于df 所需的内存,当然当reindex 用于扩展行数时更多。
      • @unutbu,不过,它在迭代容器时很有用,例如一个列表或字典,它会避免使用使代码更脏的索引......
      • @unutbu 当我分析我的约 200 列创建代码时,它确实快了很多,您能否简要解释一下为什么做 reindex 比 concat 快得多,或者只是将多个列设置为一个 numpy 数组?跨度>
      猜你喜欢
      • 2016-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-13
      • 1970-01-01
      • 2013-03-01
      • 2020-11-07
      相关资源
      最近更新 更多