Pandas read_csv 转换器 – 如何处理异常 (literal_eval SyntaxError)

Posted

技术标签:

【中文标题】Pandas read_csv 转换器 – 如何处理异常 (literal_eval SyntaxError)【英文标题】:Pandas read_csv converter – How to handle exceptions (literal_eval SyntaxError) 【发布时间】:2019-04-05 18:03:07 【问题描述】:

在 Pandas DataFrame 中,我正在读取一个 csv 文件,如下所示:

          A              B
  +--------------+---------------+
0 |              | ("t1", "t2")  |
  +--------------+---------------+
1 | ("t3", "t4") |               |
  +--------------+---------------+

其中两个单元格中有字面元组,其中两个单元格是空的。

df = pd.read_csv(my_file.csv, dtype=str, delimiter=',',
    converters='A': ast.literal_eval, 'B': ast.literal_eval)

转换器ast.literal_eval 可以很好地将文字元组转换为代码中的 Python 元组对象——但前提是没有空单元格。因为我有空单元格,所以我收到错误:

SyntaxError: 解析时出现意外的 EOF

根据这个S/O answer,我应该尝试捕获空字符串的SyntaxError异常:

ast 使用 compile 来编译源字符串(必须是 表达式)转换为 AST。如果源字符串无效 表达式(像一个空字符串),一个 SyntaxError 将由 编译。

但是,我不确定如何在 read_csv converters 的上下文中捕获单个单元格的异常。

解决此问题的最佳方法是什么?是否有其他方法可以将空字符串/单元格转换为 literal_eval 可以接受或忽略的对象?

注意:我的理解是,在可读文件中包含文字元组并不总是最好的,但在我的情况下它很有用。

【问题讨论】:

【参考方案1】:

您可以创建一个有条件地使用ast.literal_eval 的自定义函数:

from ast import literal_eval
from io import StringIO

# replicate csv file
x = StringIO("""A,B
,"('t1', 't2')"
"('t3', 't4')",""")

def literal_converter(val):
    # replace first val with '' or some other null identifier if required
    return val if val == '' else literal_eval(val)

df = pd.read_csv(x, delimiter=',', converters=dict.fromkeys('AB', literal_converter))

print(df)

          A         B
0            (t1, t2)
1  (t3, t4)          

或者,您可以使用try / except 捕获SyntaxError。此解决方案更为宽松,因为它将处理其他格式错误的语法,即 SyntaxError / ValueErrorother 而非空值的原因引起。

def literal_converter(val):
    try:
        return literal_eval(val)
    except SyntaxError, ValueError:
        return val

【讨论】:

【参考方案2】:

我会先正常读取数据,不带literal_eval()。这给了我们:

              A             B
0           NaN  ("t1", "t2")
1  ("t3", "t4")           NaN

然后我会这样做:

df.fillna('()').applymap(ast.literal_eval)

这给出了:

          A         B
0        ()  (t1, t2)
1  (t3, t4)        ()

我认为在所有单元格中都有元组很方便,即使是空单元格也是如此。这将使以后对元组进行操作更容易,例如:

newdf.sum(axis=1)

这给了你:

0    (t1, t2)
1    (t3, t4)

因为“添加”元组是连接。甚至更棘手但仍然非常有用:

newdf.A.str[0]

给你:

0    NaN
1     t3

因为pd.Series.str,尽管它看起来只能在字符串上工作,但在列表和元组上工作得很好。因此,您可以在每列的元组中高效且统一地索引元素。

【讨论】:

以上是关于Pandas read_csv 转换器 – 如何处理异常 (literal_eval SyntaxError)的主要内容,如果未能解决你的问题,请参考以下文章

如何在使用 pandas.read_csv 读取 csv 文件时将 pandas.dataframe 中的元素转换为 np.float?

pandas使用read_csv读取文件数据设置converters参数将百分比字符串转换为数字

python 在pandas中的read_csv时将值转换为demical

Pandas read_csv 转换器 – 如何处理异常 (literal_eval SyntaxError)

pandas.read_csv 将字符串转换为科学记数法中的“数字”(我不想要)

有没有办法从 pandas read_csv 中“提取”dtype 转换功能?