AttributeError:'PandasExprVisitor'对象没有属性'visit_Ellipsis',使用pandas eval

时间:2017-12-28 13:14:30

标签: python pandas eval apply

我有一系列表格:

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'

我在这里缺少什么?功能或我的数据有问题吗?

2 个答案:

答案 0 :(得分:7)

<强> TL; DR
截至v0.21,这是一个bug,也是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'

这正是造成此错误的原因。

我该怎么做才能让它发挥作用?
目前,还没有一个解决方案(问题仍然是截至12/28/2017),然而,有几个解决方法。

选项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的picked this up

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_jsonpd.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对揭露此问题的看法。

答案 1 :(得分:3)

您的数据很好,而pandas.eval是错误的,但不是您想象的那样。有一个提示in the relevant github issue page促使我仔细研究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.
        [...]

如您所见,记录的行为是将字符串传递给pd.eval,与eval / {{1的一般(和预期)行为一致函数类。你传递一个字符串,最后得到一个任意对象。

正如我所看到的那样,exec是错误的,因为它没有预先拒绝pandas.eval输入Series,导致它在面对模糊时猜测。 expr&#39;的默认缩短的事实。设计用于漂亮打印的Series可以极大地影响您的结果,这是这种情况的最好证明。

然后解决方案是从XY问题退回,并使用the right tool to convert your data,并且最好完全停止使用__repr__。即使在pandas.eval很小的工作情况下,您也无法确定未来的熊猫版本是否会打破这个功能&#34;功能&#34;完全。