我有一系列表格:
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'
我在这里缺少什么?功能或我的数据有问题吗?
答案 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
函数中找到更多详细信息。
注意
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对揭露此问题的看法。
答案 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;完全。