【问题标题】:Pandas read_csv converter – How to handle exceptions (literal_eval SyntaxError)Pandas read_csv 转换器 – 如何处理异常 (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 可以接受或忽略的对象?

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

【问题讨论】:

    标签: python string pandas csv tuples


    【解决方案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,尽管它看起来只能在字符串上工作,但在列表和元组上工作得很好。因此,您可以在每列的元组中高效且统一地索引元素。

      【讨论】:

        猜你喜欢
        • 2012-09-11
        • 2017-07-16
        • 2021-08-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-02-18
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多