【问题标题】:How to add multiple columns to pandas dataframe in one assignment?如何在一项作业中向熊猫数据框添加多列?
【发布时间】:2016-12-27 07:02:37
【问题描述】:

我是 pandas 的新手,我想弄清楚如何同时向 pandas 添加多个列。任何帮助在这里表示赞赏。理想情况下,我希望一步完成,而不是多个重复步骤......

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]"

标签: python pandas dataframe


【解决方案1】:

我本来希望你的语法也能工作。出现问题是因为当您使用列列表语法 (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 是一种比前两种更“自然”的方式来创建新数据框,但新列将按字母顺序排序(至少 before Python 3.6 or 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

注意:其中许多选项已包含在其他答案中:Add multiple columns to DataFrame and set them equal to an existing columnIs it possible to add several columns at once to a pandas DataFrame?Add multiple empty columns to pandas DataFrame

【讨论】:

  • 不会接近 #7 (.reindex) 更改数据框的索引吗?为什么有人会在添加列时不必要地更改索引,除非它是一个明确的目标......
  • .reindex()columns 参数一起使用,因此它只会更改“索引”列(名称)。它不会改变行索引。
  • 如果您使用带有join 的选项,请确保您的索引中没有重复项(或首先使用reset_index)。可能会为您节省几个小时的调试时间。
  • @smci .assign() 当然更灵活,但是如果您只是要添加几列,则必须简单地将它们按正确的顺序放入嵌套的数组列表中或作为 df 之类的在#2中,然后分配。我只是不明白为什么我应该用.assign() 拆分每个列分配。 #2 是我每次分配列时在实践中所做的:df[['column_new_1', 'column_new_2', 'column_new_3']] = [[np.array(),np.array(),np.array()]],甚至不需要 #2 的 pd.DataFrame()。不需要重复的 df[] (#1) 也不需要单独的列分配 (#6)。
  • 一些性能指标真的会让这篇文章成为黄金。
【解决方案2】:

您可以将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

【讨论】:

  • 有没有办法保持列的特定顺序?
  • 您可以通过多次调用 assign 来维护早期版本的 Python 的特定排序:df.assign(**{'col_new_1': np.nan}).assign(**{'col2_new_2': 'dogs'}).assign(**{'col3_new_3': 3})
  • 如果列名仅包含合法变量名的字符串:df.assign(col_new_1=np.nan, col2_new_2='dogs', col3_new_3=3)。这样可以维持秩序。
【解决方案3】:

使用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

【讨论】:

  • 如果有办法一步完成第二部分 - 以列中的常量值为例。
【解决方案4】:

使用列表理解,pd.DataFramepd.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)

【讨论】:

  • 请注意,concat 将生成一个新的数据框,而不是向现有的数据框添加列。
【解决方案5】:

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

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

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

【讨论】:

    【解决方案6】:

    只想在@Matthias Fripp 的回答中指出选项 2

    (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 中不包含列,则会引发异常。 这种方式也可以设置多列。 您可能会发现这对于将转换(in-place)应用于列的子集很有用。

    【讨论】:

    • 我认为这是多列分配的标准。令我惊讶的部分是pd.DataFrame([[np.nan, 'dogs', 3]], index=df.index) 复制了它被赋予的一行以创建一个与索引长度相同的整个数据帧。
    【解决方案7】:

    .assign()的字典映射:

    这是在处理许多列时为新列分配值的最易读和动态的方式。

    import pandas as pd
    import numpy as np
    
    new_cols = ["column_new_1", "column_new_2", "column_new_3"]
    new_vals = [np.nan, "dogs", 3]
    # Map new columns as keys and new values as values
    col_val_mapping = dict(zip(new_cols, new_vals))
    # Unpack new column/new value pairs and assign them to the data frame
    df = df.assign(**col_val_mapping)
    

    如果您只是尝试将新列值初始化为空,因为您不知道这些值将是什么,或者您有许多新列。

    import pandas as pd
    import numpy as np
    
    new_cols = ["column_new_1", "column_new_2", "column_new_3"]
    new_vals = [None for item in new_cols]
    # Map new columns as keys and new values as values
    col_val_mapping = dict(zip(new_cols, new_vals))
    # Unpack new column/new value pairs and assign them to the data frame
    df = df.assign(**col_val_mapping)
    

    【讨论】:

      【解决方案8】:

      如果您只想添加空的新列,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')
      

      否则去zeros 回答assign

      【讨论】:

        【解决方案9】:

        我不习惯使用“索引”等等...可能如下所示

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

        【讨论】:

          【解决方案10】:

          如果您希望每列有不同的值,并且您不介意在之前的行上制作字典,则可以从字典中实例化值。

          >>> import pandas as pd
          >>> import numpy as np
          >>> df = pd.DataFrame({
            'col_1': [0, 1, 2, 3], 
            'col_2': [4, 5, 6, 7]
          })
          >>> df
             col_1  col_2
          0      0      4
          1      1      5
          2      2      6
          3      3      7
          >>> cols = {
            'column_new_1':np.nan,
            'column_new_2':'dogs',
            'column_new_3': 3
          }
          >>> df[list(cols)] = pd.DataFrame(data={k:[v]*len(df) for k,v in cols.items()})
          >>> df
             col_1  col_2  column_new_1 column_new_2  column_new_3
          0      0      4           NaN         dogs             3
          1      1      5           NaN         dogs             3
          2      2      6           NaN         dogs             3
          3      3      7           NaN         dogs             3
          

          不一定比公认的答案更好,但它是另一种尚未列出的方法。

          【讨论】:

            猜你喜欢
            • 2021-06-11
            • 2018-12-19
            • 2021-06-27
            • 2019-08-29
            • 2022-09-24
            • 1970-01-01
            • 2021-06-25
            相关资源
            最近更新 更多