在Pandas中分配给容器
我想把Pandas中某一列里的None
值替换成一个空列表。
需要注意的是,这一列中有些值可能已经是空列表了,我不想去改动那些。
我试过:
indices = np.equal(df[col],None)
df[col][indices] = []
还有
indices = np.equal(df[col],None)
df[col][indices] = list()
但是这两种方法都失败了,错误信息是:
ValueError: Length of replacements must equal series length
为什么会这样?我该怎么把那些特定的行更新为一个空列表呢?
2 个回答
编辑:我保留了我原来的回答,但我没有测试就发上来了,结果对我来说并不管用。
import pandas as pd
import numpy as np
ser1 = pd.Series(['hi',None,np.nan])
ser2 = pd.Series([5,7,9])
df = pd.DataFrame([ser1,ser2]).T
我知道这有点糟糕。而且,显然DataFrame的构造函数(但不是Series的构造函数)会把None转换成np.nan。我也不知道为什么。
df.loc[1,0] = None
所以现在我们有了
0 1
0 'hi' 5
1 None 7
2 NaN 9
df.columns = ['col1','col2']
mask = np.equal(df['col1'], None)
df.loc[mask, 'col1'] = []
但这并没有赋值。数据框看起来和之前一样。我按照文档推荐的用法来做,赋值基本类型(字符串和数字)是有效的。所以对我来说,问题出在给数据框的条目赋值对象上。我也不知道怎么回事。
(原始回答)
两件事:
- 我不太熟悉
np.equal
,但如果你想捕捉所有空值,pandas.isnull()
也应该有效。 - 你正在做一种叫“链式赋值”的操作。我不太理解这个问题,但我知道它不管用。在文档中有说明.
试试这个:
mask = pandas.isnull(df[col])
df.loc[mask, col] = list()
或者,如果你只想捕捉None
而不想捕捉np.nan
:
mask = np.equal(df[col].values, None)
df.loc[mask, col] = list()
注意:虽然pandas.isnull
在数据框、系列和数组中都能正常处理None
,但numpy.equal
在数据框和数组中才会如预期工作。一个全是None
的pandas系列不会对其中任何一个返回True。这是因为None
只在某些情况下表现得像np.nan
。请参见BUG: None不等于None #20442
在作业中使用内嵌列表是不被允许的,而且也不推荐这样做。
如果你从头开始创建,是可以做到的。
In [50]: DataFrame({ 'A' : [[],[],1]})
Out[50]:
A
0 []
1 []
2 1
[3 rows x 1 columns]
之所以不允许这样做,是因为没有索引(比如在numpy中),你可能会遇到这样的情况:
In [51]: df = DataFrame({ 'A' : [1,2,3] })
In [52]: df.loc[df['A'] == 2] = [ 5 ]
In [53]: df
Out[53]:
A
0 1
1 5
2 3
[3 rows x 1 columns]
你可以进行一个赋值操作,其中掩码中为真的值的数量必须和右边的列表/元组/数组的长度相等(也就是你要设置的值)。Pandas允许这样做,也允许长度正好等于左边的长度,或者是一个单一的数值。其他情况都是不被允许的,因为这样会造成歧义(比如你是想对齐还是不对齐?)
举个例子,想象一下:
In [54]: df = DataFrame({ 'A' : [1,2,3] })
In [55]: df.loc[df['A']<3] = [5]
ValueError: cannot set using a list-like indexer with a different length than the value
一个长度为0的列表/元组/数组被认为是错误的,这不是因为做不到,而是通常是用户的错误,没办法明确该怎么做。
总之,不要在pandas对象内部使用列表。这不仅效率低下,还会让理解变得困难甚至不可能。