Python pandas 将列表插入单元格
我有一个列表 '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'] = abc
或 df3.loc[1,'B'] = abc
时,就会出现错误信息。
另一个数据框:
df4 =
A B
0 'bla' NaN
1 'bla bla' NaN
这些插入操作完全没问题: df.loc[1,'B'] = abc
或 df4.loc[1,'B'] = abc
。
9 个回答
我也遇到了这个问题:
ValueError: Must have equal len keys and value when setting with an iterable
,
在我的情况下,使用 .at 代替 .loc 并没有什么区别,但强制设置数据框列的数据类型解决了这个问题:
df['B'] = df['B'].astype(object)
这样我就可以把列表、numpy 数组以及各种东西作为单个单元格的值放进我的数据框里了。
快速解决方法
只需把这个列表放在一个新的列表里,就像下面数据表中的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]
Pandas >= 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
类型,而列表是 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]
你可以在 这里 阅读更多关于为什么这样做有效的信息。
因为从0.21.0版本开始,set_value
这个功能已经被淘汰了,所以现在你应该使用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
df3.set_value(1, 'B', abc)
这个方法可以在任何数据表中使用。要注意列 'B' 的数据类型。例如,如果你想往一个浮点数类型的列里插入一个列表,那是行不通的。在这种情况下,可以用 df['B'] = df['B'].astype(object)
这个方法来解决问题,把 'B' 列的类型改成对象类型。