Pandas read_csv converter - 如何处理异常(literal_eval SyntaxError)

Win*_*ags 3 python csv literals pandas

进入Pandas DataFrame,我正在读一个csv文件,看起来像:

          A              B
  +--------------+---------------+
0 |              | ("t1", "t2")  |
  +--------------+---------------+
1 | ("t3", "t4") |               |
  +--------------+---------------+
Run Code Online (Sandbox Code Playgroud)

其中两个单元格中包含文字元组,其中两个单元格为空.

df = pd.read_csv(my_file.csv, dtype=str, delimiter=',',
    converters={'A': ast.literal_eval, 'B': ast.literal_eval})
Run Code Online (Sandbox Code Playgroud)

转换器ast.literal_eval可以很好地将文字元组转换为代码中的Python元组对象 - 但只要没有空单元格.因为我有空单元格,我得到错误:

SyntaxError:解析时意外的EOF

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

ast使用compile将源字符串(必须是表达式)编译成AST.如果源字符串不是有效表达式(如空字符串),则将通过编译引发SyntaxError.

但是,我不确定如何捕获单个单元格的异常read_csv converters.

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

注意:我的理解是在可读文件中使用文字元组并不总是最好的,但在我看来它很有用.

jpp*_*jpp 6

您可以创建一个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)          
Run Code Online (Sandbox Code Playgroud)

或者,您可以使用try/except来捕获SyntaxError. 该解决方案是更为宽松,因为它会处理其他的语法错误,即SyntaxError/ValueError所造成的原因不是空值。

def literal_converter(val):
    try:
        return literal_eval(val)
    except SyntaxError, ValueError:
        return val
Run Code Online (Sandbox Code Playgroud)


Joh*_*nck 5

我会先正常读取数据,没有literal_eval().这给了我们:

              A             B
0           NaN  ("t1", "t2")
1  ("t3", "t4")           NaN
Run Code Online (Sandbox Code Playgroud)

然后我会这样做:

df.fillna('()').applymap(ast.literal_eval)
Run Code Online (Sandbox Code Playgroud)

这使:

          A         B
0        ()  (t1, t2)
1  (t3, t4)        ()
Run Code Online (Sandbox Code Playgroud)

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

newdf.sum(axis=1)
Run Code Online (Sandbox Code Playgroud)

哪个给你:

0    (t1, t2)
1    (t3, t4)
Run Code Online (Sandbox Code Playgroud)

因为"添加"元组是串联的.甚至更棘手,但仍然非常有用:

newdf.A.str[0]
Run Code Online (Sandbox Code Playgroud)

给你:

0    NaN
1     t3
Run Code Online (Sandbox Code Playgroud)

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