将列表插入到单元格中

我有一个列表“ 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]

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

如果数据框架中的列只包含整数值和/或 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

212364 次浏览

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

由于 set_value自0.21.0版以来一直是 不赞成,因此现在应该使用 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

正如本文 熊猫: 如何在数据框架中存储列表?中提到的,数据框中的 dtype 可能会影响结果,以及调用数据框或不指派给它。

熊猫 > = 0.21

已弃用 set_value 现在可以使用 ABC1按标签进行设置,使用 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,而列表是 object,所以存在不匹配。在这种情况下,您必须首先将列转换为对象。

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

你可以阅读更多关于为什么这个工作 给你。

快速解决

只需将列表包含在一个新列表中,就像下面的数据框中的 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]

还有

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

使用。而不是。在我的例子中,loc 没有起到任何作用,但是强制使用 dataframe 列的数据类型起到了作用:

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

然后,我可以设置列表,数字数组和各种各样的东西作为单元格值在我的数据框架。

我有个很简单的解决方案。

创建一个临时类来包装列表对象,然后从类中调用该值。

这里有一个实际的例子:

  1. 假设您想将 list 对象插入到数据框中。
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.


创建一个假的类来做这件事可能看起来很麻烦,但是它可以有一些实际的应用。例如,当返回值为 list 时,可以将其与 apply一起使用。

熊猫通常会拒绝在单元格中插入列表,但是如果你使用这种方法,你可以强制插入。

我更喜欢 。在。 loc。需要注意的是,目标列需要一个 dtype(object) ,它可以处理列表。

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

首先将单元格设置为空白。接下来使用 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)