AttributeError:使用熊猫eval,“ PandasExprVisitor”对象没有属性“ visit_Ellipsis”
问题内容:
我有一系列的表格:
s
0 [133, 115, 3, 1]
1 [114, 115, 2, 3]
2 [51, 59, 1, 1]
dtype: object
注意,它的元素是 字符串 :
s[0]
'[133, 115, 3, 1]'
我试图用来pd.eval
将此字符串解析为列表的一列。这适用于此样本数据。
pd.eval(s)
array([[133, 115, 3, 1],
[114, 115, 2, 3],
[51, 59, 1, 1]], dtype=object)
但是,在更大的数据(10K的数量级)上,这很惨!
len(s)
300000
pd.eval(s)
AttributeError: 'PandasExprVisitor' object has no attribute 'visit_Ellipsis'
我在这里想念什么?函数或数据有问题吗?
问题答案:
TL; DR
截至v0.21
,这是一个错误,并且是GitHub上的一个未解决问题。参见GH16289。
为什么会出现此错误?
(很可能)这是pd.eval
的错,它不能解析具有100多行的序列。这是一个例子。
len(s)
300000
pd.eval(s.head(100)) # returns a parsed result
鉴于,
pd.eval(s.head(101))
AttributeError: 'PandasExprVisitor' object has no attribute 'visit_Ellipsis'
无论解析器还是引擎,此问题仍然存在。
这个错误是什么意思?
当传递的行超过100行时,对其进行pd.eval
操作__repr__
,而不是对其中包含的对象进行操作(这是导致此错误的原因)。所述__repr__
截短的行,具有替换它们...
(省略号)。该省略号被引擎误解为Ellipsis
对象-
...
Ellipsis
pd.eval('...')
AttributeError: 'PandasExprVisitor' object has no attribute 'visit_Ellipsis'
这正是导致此错误的原因。
我该怎么做才能使它正常工作?
目前,尚无解决方案(该问题截至2017年12月28日仍未解决), 但是 ,有一些解决方法。
选项1 如果可以保证没有任何格式错误的字符串,则此选项应立即可用。
ast.literal_eval
from ast import literal_eval
s.apply(literal_eval)
0 [133, 115, 3, 1]
1 [114, 115, 2, 3]
2 [51, 59, 1, 1]
dtype: object
如果可能出现数据格式错误,则需要编写一些错误处理代码。您可以使用函数来做到这一点-
def safe_parse(x):
try:
return literal_eval(x)
except (SyntaxError, ValueError):
return np.nan # replace with any suitable placeholder value
将此功能传递给apply
-
s.apply(safe_parse)
0 [133, 115, 3, 1]
1 [114, 115, 2, 3]
2 [51, 59, 1, 1]
dtype: object
ast
适用于任意数量的行,速度很慢,但可靠。您也可以将pd.json.loads
JSON数据用于,方法与相同literal_eval
。
选项2
yaml.load
解析简单数据的另一个不错的选择,我前一阵子是从@ayhan那里选出来的。
import yaml
s.apply(yaml.load)
0 [133, 115, 3, 1]
1 [114, 115, 2, 3]
2 [51, 59, 1, 1]
dtype: object
我尚未在更复杂的结构上对此进行过测试,但这对于几乎所有基本的数据字符串表示形式均适用。
您可以在此处找到PyYAML的文档。向下滚动一点,您将找到有关该load
功能的更多详细信息。
注意
- 如果您使用的是JSON数据,则可能适合使用
pd.read_json
或pd.io.json.json_normalize
从头开始读取文件。 - 您还可以在读取数据时执行解析,方法是
read_csv
-s = pd.read_csv(converters=literal_eval, squeeze=True)
该converters
参数将在读取的列上应用传递给该列的函数,因此您以后不必处理解析。
- 继续上述要点,如果您正在使用数据框,请传递
dict
-df = pd.read_csv(converters={'col' : literal_eval})
col
您还可以传递pd.json.loads
(对于json数据)或pd.eval
(如果您有100行或更少的行),则将其解析在哪里。
感谢MaxU和Moondra发现此问题。