【问题标题】:Python pandas insert list into a cellPython pandas将列表插入单元格
【发布时间】:2014-12-16 11:23:23
【问题描述】:

我有一个列表“abc”和一个数据框“df”:

abc = ['foo', 'bar']
df =
    A  B
0  12  NaN
1  23  NaN

我想将列表插入单元格 1B,所以我想要这个结果:

    A  B
0  12  NaN
1  23  ['foo', 'bar']

我可以这样做吗?

1) 如果我使用这个:

df.ix[1,'B'] = abc

我收到以下错误消息:

ValueError: Must have equal len keys and value when setting with an iterable

因为它试图将列表(包含两个元素)插入行/列而不是单元格。

2) 如果我使用这个:

df.ix[1,'B'] = [abc]

然后它会插入一个列表,其中只有一个元素是“abc”列表 ([['foo', 'bar']])。

3) 如果我使用这个:

df.ix[1,'B'] = ', '.join(abc)

然后它插入一个字符串:(foo, bar)但不是一个列表。

4) 如果我使用这个:

df.ix[1,'B'] = [', '.join(abc)]

然后它插入一个列表,但它只有一个元素(['foo, bar']),但不是我想要的两个(['foo', 'bar'])。

感谢您的帮助!


编辑

我的新数据框和旧列表:

abc = ['foo', 'bar']
df2 =
    A    B         C
0  12  NaN      'bla'
1  23  NaN  'bla bla'

另一个数据框:

df3 =
    A    B         C                    D
0  12  NaN      'bla'  ['item1', 'item2']
1  23  NaN  'bla bla'        [11, 12, 13]

我想将“abc”列表插入df2.loc[1,'B'] 和/或df3.loc[1,'B']

如果数据框的列仅包含整数值和/或 NaN 值和/或列表值,则将列表插入单元格效果很好。如果数据框的列仅包含字符串值和/或 NaN 值和/或列表值,则将列表插入单元格效果很好。但是,如果数据框包含具有整数和字符串值的列以及其他列,那么如果我使用它,则会出现错误消息:df2.loc[1,'B'] = abcdf3.loc[1,'B'] = abc

另一个数据框:

df4 =
          A     B
0      'bla'  NaN
1  'bla bla'  NaN

这些插件完美运行:df.loc[1,'B'] = abcdf4.loc[1,'B'] = abc

【问题讨论】:

  • 你用的是什么版本的熊猫?以下使用熊猫0.15.0df.loc[1,'b'] = ['foo','bar']
  • 谢谢!我使用 Python 2.7,我尝试了 pandas 0.14.0 和 0.15.0,它与上面的测试数据一起工作。但是,如果我有一个带有一些整数值的“C”列怎么办? 'A' 有字符串。有一个整数列和一个 srting 列我得到同样的错误: ValueError: Must have equal len keys and value when setting with an iterable
  • 你将不得不发布数据和代码来解释和展示你的意思

标签: python list pandas insert dataframe


【解决方案1】:

由于自 0.21.0 版起 set_value 一直是 deprecated,您现在应该使用 at。它可以将列表插入单元格,而无需像loc 那样引发ValueError。我认为这是因为at 总是 引用单个值,而loc 可以引用值以及行和列。

df = pd.DataFrame(data={'A': [1, 2, 3], 'B': ['x', 'y', 'z']})

df.at[1, 'B'] = ['m', 'n']

df =
    A   B
0   1   x
1   2   [m, n]
2   3   z

您还需要确保要插入的具有dtype=object。例如

>>> df = pd.DataFrame(data={'A': [1, 2, 3], 'B': [1,2,3]})
>>> df.dtypes
A    int64
B    int64
dtype: object

>>> df.at[1, 'B'] = [1, 2, 3]
ValueError: setting an array element with a sequence

>>> df['B'] = df['B'].astype('object')
>>> df.at[1, 'B'] = [1, 2, 3]
>>> df
   A          B
0  1          1
1  2  [1, 2, 3]
2  3          3

【讨论】:

    【解决方案2】:

    熊猫 >= 0.21

    set_value 已被弃用。 您现在可以使用DataFrame.at 按标签设置,DataFrame.iat 按整数位置设置。

    使用at/iat 设置单元格值

    # Setup
    >>> df = pd.DataFrame({'A': [12, 23], 'B': [['a', 'b'], ['c', 'd']]})
    >>> df
    
        A       B
    0  12  [a, b]
    1  23  [c, d]
    
    >>> df.dtypes
    
    A     int64
    B    object
    dtype: object
    

    如果您想将“B”列的第二行中的值设置为某个新列表,请使用DataFrame.at

    >>> df.at[1, 'B'] = ['m', 'n']
    >>> df
    
        A       B
    0  12  [a, b]
    1  23  [m, n]
    

    您也可以使用DataFrame.iat按整数位置设置

    >>> df.iat[1, df.columns.get_loc('B')] = ['m', 'n']
    >>> df
    
        A       B
    0  12  [a, b]
    1  23  [m, n]
    

    如果我收到ValueError: setting an array element with a sequence 怎么办?

    我将尝试通过以下方式重现此内容:

    >>> df
        A   B
    0  12 NaN
    1  23 NaN
    
    >>> df.dtypes
    A      int64
    B    float64
    dtype: object
    
    >>> df.at[1, 'B'] = ['m', 'n']
    # ValueError: setting an array element with a sequence.
    

    这是因为你的对象是float64 dtype,而列表是objects,所以那里不匹配。在这种情况下,您必须先将列转换为对象。

    >>> df['B'] = df['B'].astype(object)
    >>> df.dtypes
    
    A     int64
    B    object
    dtype: object
    

    然后,它起作用了:

    >>> df.at[1, 'B'] = ['m', 'n']
    >>> df
        
        A       B
    0  12     NaN
    1  23  [m, n]
    

    有可能,但很老套

    更古怪的是,我发现如果你传递嵌套列表,你可以破解 DataFrame.loc 来实现类似的目标。

    >>> df.loc[1, 'B'] = [['m'], ['n'], ['o'], ['p']]
    >>> df
    
        A             B
    0  12        [a, b]
    1  23  [m, n, o, p]
    

    您可以阅读更多关于为什么这样做here.

    【讨论】:

      【解决方案3】:

      df3.set_value(1, 'B', abc) 适用于任何数据框。注意“B”列的数据类型。例如,列表不能插入到浮点列中,在这种情况下df['B'] = df['B'].astype(object) 可以提供帮助。

      【讨论】:

      • 请注意,此命令已被弃用。下面有更新。
      【解决方案4】:

      快速解决方法

      只需将列表包含在一个新列表中,就像下面数据框中的 col2 所做的那样。它起作用的原因是python获取外部列表(列表)并将其转换为一列,就好像它包含普通标量项一样,在我们的例子中是列表而不是普通标量。

      mydict={'col1':[1,2,3],'col2':[[1, 4], [2, 5], [3, 6]]}
      data=pd.DataFrame(mydict)
      data
      
      
         col1     col2
      0   1       [1, 4]
      1   2       [2, 5]
      2   3       [3, 6]
      

      【讨论】:

      • 我在 col2 中得到了空列表,即使我填充了它们
      【解决方案5】:

      也得到

      ValueError: Must have equal len keys and value when setting with an iterable,

      在我的情况下,使用 .at 而不是 .loc 没有任何区别,但是强制数据框列的数据类型起到了作用:

      df['B'] = df['B'].astype(object)
      

      然后我可以在我的数据框中将列表、numpy 数组和各种东西设置为单个单元格值。

      【讨论】:

        【解决方案6】:

        正如这篇文章中提到的pandas: how to store a list in a dataframe?;数据帧中的 dtypes 可能会影响结果,以及调用数据帧或不分配给。

        【讨论】:

          【解决方案7】:

          我有一个实施起来非常简单的解决方案。

          创建一个临时类只是为了包装列表对象,然后从类中调用值。

          这是一个实际的例子:

          1. 假设您要将列表对象插入到数据框中。
          df = pd.DataFrame([
              {'a': 1},
              {'a': 2},
              {'a': 3},
          ])
          
          df.loc[:, 'b'] = [
              [1,2,4,2,], 
              [1,2,], 
              [4,5,6]
          ] # This works. Because the list has the same length as the rows of the dataframe
          
          df.loc[:, 'c'] = [1,2,4,5,3] # This does not work. 
          
          >>> ValueError: Must have equal len keys and value when setting with an iterable
          
          ## To force pandas to have list as value in each cell, wrap the list with a temporary class.
          
          class Fake(object):
              def __init__(self, li_obj):
                  self.obj = li_obj
          
          df.loc[:, 'c'] = Fake([1,2,5,3,5,7,]) # This works. 
          
          df.c = df.c.apply(lambda x: x.obj) # Now extract the value from the class. This works. 
          
          

          创建一个伪类来执行此操作可能看起来很麻烦,但它可以有一些实际应用。例如,当返回值为列表时,您可以将其与 apply 一起使用。

          Pandas 通常会拒绝将列表插入单元格,但如果您使用此方法,则可以强制插入。

          【讨论】:

            【解决方案8】:

            我更喜欢.at.loc。需要注意的是,目标列需要一个dtypeobject),它可以处理列表。

            import numpy as np
            import pandas as pd
            
            df = pd.DataFrame({
                'A': [0, 1, 2, 3],
                'B': np.array([np.nan]*3 + [[3, 33]], dtype=object),
                })
            print('df to start with:', df, '\ndtypes:', df.dtypes, sep='\n')
            
            df.at[0, 'B'] = [0, 100]  # at assigns single elemnt
            df.loc[1, 'B'] = [[ [1, 11] ]]  # loc expects 2d input
            
            print('df modified:', df, '\ndtypes:', df.dtypes, sep='\n')
            

            输出

            df to start with:
               A        B
            0  0      NaN
            1  1      NaN
            2  2      NaN
            3  3  [3, 33]
            
            dtypes:
            A     int64
            B    object
            dtype: object
            df modified:
               A          B
            0  0   [0, 100]
            1  1  [[1, 11]]
            2  2        NaN
            3  3    [3, 33]
            
            dtypes:
            A     int64
            B    object
            dtype: object
            

            【讨论】:

              【解决方案9】:

              首先将单元格设置为空白。接下来使用 at 将 abc 列表分配给 1 处的单元格,'B'

              abc = ['foo', 'bar']
              df =pd.DataFrame({'A':[12,23],'B':[np.nan,np.nan]})
              df.loc[1,'B']=''
              df.at[1,'B']=abc
              print(df)
              

              【讨论】:

                猜你喜欢
                • 2022-01-20
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2020-08-15
                • 1970-01-01
                相关资源
                最近更新 更多