AttributeError: 'PandasExprVisitor' object has no attribute 'visit_Ellipsis', using pandas eval
AttributeError: 'PandasExprVisitor' object has no attribute 'visit_Ellipsis', using pandas eval
我有一系列的表格:
s
0 [133, 115, 3, 1]
1 [114, 115, 2, 3]
2 [51, 59, 1, 1]
dtype: object
注意它的元素是 strings:
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
这无疑是 eval 中的一个错误。查看开放 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'
无论使用何种解析器或引擎,此问题仍然存在。
这个错误是什么意思?
pd.eval
对系列的 __repr__
进行操作,而不是对其中包含的对象进行操作(这是此错误的原因)。 __repr__
截断行,用 ...
(省略号)替换它们。该省略号被引擎误解为 Ellipsis
对象 -
...
Ellipsis
pd.eval('...')
AttributeError: 'PandasExprVisitor' object has no attribute 'visit_Ellipsis'
pd.eval
技术上不应该解析一系列字符串(文档中提到它是为了接收字符串)并且(如接受的答案所述)将尝试对结果进行合理的猜测完全拒绝输入。
这是预期的行为还是不完整的行为(许多 pandas 方法根据输入以不同的方式运行 - eval 可以通过将自身映射到每一行来处理一系列,这就是我最初假设的方式无论如何这是有效的)有待讨论,因为有一个未解决的问题跟踪这个。
我该怎么做才能让它发挥作用?
目前,没有解决方案(该问题截至 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 的文档 here。向下滚动一点,您会发现有关 load
函数的更多详细信息。
备注
如果您正在处理 JSON 数据,那么开始使用 pd.read_json
or 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 发现了这个问题。
你的数据很好,pandas.eval
有问题,但不是你想的那样。有提示in the relevant github issue page that urged me to take a closer look at the documentation。
pandas.eval(expr, parser='pandas', engine=None, truediv=True, local_dict=None,
global_dict=None, resolvers=(), level=0, target=None, inplace=False)
Evaluate a Python expression as a string using various backends.
Parameters:
expr: str or unicode
The expression to evaluate. This string cannot contain any Python
statements, only Python expressions.
[...]
如您所见,记录的行为是将 strings 传递给 pd.eval
,与 [=13= 的一般(和预期)行为一致]/exec
class 个函数。你传递一个字符串,最后得到一个任意对象。
在我看来,pandas.eval
是有问题的,因为它不会预先拒绝 Series
输入 expr
,导致它在面对歧义时进行猜测。 Series
' __repr__
设计用于漂亮打印的默认缩短会极大地影响您的结果,这一事实就是这种情况的最好证明。
解决方案是从 XY 问题退后一步,使用 ,最好完全停止使用 pandas.eval
。即使在 Series
很小的工作情况下,你也不能真正确定未来的 pandas 版本不会完全破坏这个 "feature"。
我有一系列的表格:
s
0 [133, 115, 3, 1]
1 [114, 115, 2, 3]
2 [51, 59, 1, 1]
dtype: object
注意它的元素是 strings:
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
这无疑是 eval 中的一个错误。查看开放 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'
无论使用何种解析器或引擎,此问题仍然存在。
这个错误是什么意思?
pd.eval
对系列的 __repr__
进行操作,而不是对其中包含的对象进行操作(这是此错误的原因)。 __repr__
截断行,用 ...
(省略号)替换它们。该省略号被引擎误解为 Ellipsis
对象 -
...
Ellipsis
pd.eval('...')
AttributeError: 'PandasExprVisitor' object has no attribute 'visit_Ellipsis'
pd.eval
技术上不应该解析一系列字符串(文档中提到它是为了接收字符串)并且(如接受的答案所述)将尝试对结果进行合理的猜测完全拒绝输入。
这是预期的行为还是不完整的行为(许多 pandas 方法根据输入以不同的方式运行 - eval 可以通过将自身映射到每一行来处理一系列,这就是我最初假设的方式无论如何这是有效的)有待讨论,因为有一个未解决的问题跟踪这个。
我该怎么做才能让它发挥作用?
目前,没有解决方案(该问题截至 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
解析简单数据的另一个很好的选择,我
import yaml
s.apply(yaml.load)
0 [133, 115, 3, 1]
1 [114, 115, 2, 3]
2 [51, 59, 1, 1]
dtype: object
我没有在更复杂的结构上对此进行测试,但这应该适用于几乎所有基本的数据字符串表示形式。
您可以找到 PyYAML 的文档 here。向下滚动一点,您会发现有关 load
函数的更多详细信息。
备注
如果您正在处理 JSON 数据,那么开始使用
pd.read_json
orpd.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 发现了这个问题。
你的数据很好,pandas.eval
有问题,但不是你想的那样。有提示in the relevant github issue page that urged me to take a closer look at the documentation。
pandas.eval(expr, parser='pandas', engine=None, truediv=True, local_dict=None,
global_dict=None, resolvers=(), level=0, target=None, inplace=False)
Evaluate a Python expression as a string using various backends.
Parameters:
expr: str or unicode
The expression to evaluate. This string cannot contain any Python
statements, only Python expressions.
[...]
如您所见,记录的行为是将 strings 传递给 pd.eval
,与 [=13= 的一般(和预期)行为一致]/exec
class 个函数。你传递一个字符串,最后得到一个任意对象。
在我看来,pandas.eval
是有问题的,因为它不会预先拒绝 Series
输入 expr
,导致它在面对歧义时进行猜测。 Series
' __repr__
设计用于漂亮打印的默认缩短会极大地影响您的结果,这一事实就是这种情况的最好证明。
解决方案是从 XY 问题退后一步,使用 pandas.eval
。即使在 Series
很小的工作情况下,你也不能真正确定未来的 pandas 版本不会完全破坏这个 "feature"。