Python pandas 将列表插入单元格
- 2025-01-10 08:47:00
- admin 原创
- 95
问题描述:
我有一个列表“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']
and/or中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
。
解决方案 1:
由于自 0.21.0 版以来set_value
已弃用,您现在应该使用at
。它可以将列表插入单元格而不会ValueError
像loc
那样引发。我认为这是因为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,而列表是object
s,因此存在不匹配。在这种情况下,您需要做的是先将列转换为对象。
>>> 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]
您可以在此处阅读有关其工作原理的更多信息。
解决方案 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]
解决方案 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: 如何将列表存储在数据框中?中提到的;数据框中的数据类型可能会影响结果,以及调用数据框或不分配给数据框。
解决方案 7:
我有一个非常容易实现的解决方案。
创建一个临时类来包装列表对象,然后从该类中调用该值。
以下是一个实际的例子:
假设您想将列表对象插入数据框。
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。需要注意的是,目标列需要一个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, '
dtypes:', df.dtypes, sep='
')
df.at[0, 'B'] = [0, 100] # at assigns single elemnt
df.loc[1, 'B'] = [[ [1, 11] ]] # loc expects 2d input
print('df modified:', df, '
dtypes:', df.dtypes, sep='
')
输出
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)