【问题标题】:Reading CSV files with python (pandas) when there is HTML escaped string in there当其中有 HTML 转义字符串时,使用 python (pandas) 读取 CSV 文件
【发布时间】:2017-03-16 22:16:12
【问题描述】:

我正在尝试使用 pandas read_csv 读取 CSV 文件。数据看起来像这样(示例)

thing;weight;price;colour
apple;1;2;red
m & m's;0;10;several
cherry;0,5;2;dark red

由于 HTML 转义的 & 符号,根据 pandas,第二行将包含 5 个字段。我如何确保正确读取该内容?

这里的示例几乎是我的数据的样子:分隔符是“;”,没有字符串引号,cp1251 编码。 我收到的数据非常大,读取它必须一步完成(意味着在 python 之外没有预处理)。

我在 pandas 文档中没有找到任何参考资料(我使用的是 pandas 0.19 和 python 3.5.1)。有什么建议?提前致谢。

【问题讨论】:

  • 是 &amp 总是在第一列,是你想从数据集中完全删除的东西吗?
  • 不,& (and > and < and ä things) 到处都是。

标签: python python-3.x csv pandas


【解决方案1】:

Unescape the html character references:

import html
with open('data.csv', 'r', encoding='cp1251') as f, open('data-fixed.csv', 'w') as g:
    content = html.unescape(f.read())
    g.write(content)
print(content)
# thing;weight;price;colour
# apple;1;2;red
# m & m's;0;10;several
# cherry;0,5;2;dark red

然后以通常的方式加载 csv:

import pandas as pd
df = pd.read_csv('data-fixed.csv', sep=';')
print(df)

产量

     thing weight  price    colour
0    apple      1      2       red
1  m & m's      0     10   several
2   cherry    0,5      2  dark red

虽然数据文件“相当大”,但您似乎有足够的内存将其读入 DataFrame。因此,您还应该有足够的内存将文件读入单个字符串:f.read()。一次调用 html.unescape 转换 HTML 比在许多较小的字符串上调用 html.unescape 更高效。这就是为什么我建议使用

with open('data.csv', 'r', encoding='cp1251') as f, open('data-fixed.csv', 'w') as g:
    content = html.unescape(f.read())
    g.write(content)

而不是类似的东西

with open('data.csv', 'r', encoding='cp1251') as f, open('data-fixed.csv', 'w') as g:
    for line in f:
        g.write(html.unescape(line))

如果您需要多次读取此数据文件,则需要修复它(并保存它 到磁盘),因此您无需在每次解析时都调用html.unescape 数据。这就是为什么我建议将未转义的内容写入data-fixed.csv

如果读取此数据是一次性任务,并且您希望避免写入磁盘的性能或资源成本,那么您可以使用 StringIO(内存中类似文件的对象):

from io import StringIO
import html
import pandas as pd

with open('data.csv', 'r', encoding='cp1251') as f:
    content = html.unescape(f.read())
df = pd.read_csv(StringIO(content), sep=';')
print(df)

【讨论】:

  • df = pd.read_csv(content, sep=';') 可以在不写入(可能很大)文件的情况下工作吗?
  • @IanS:您需要将 content 包装在 StringIO 中:from io import StringIOdf = pd.read_csv(StringIO(content), sep=';')
【解决方案2】:

您可以使用正则表达式作为pandas.read_csv 的分隔符 在您的具体情况下,您可以尝试:

pd.read_csv("test.csv",sep = "(?<!&amp);")
#         thing weight  price    colour
#0        apple      1      2       red
#1  m &amp; m's      0     10   several
#2       cherry    0,5      2  dark red

选择前面没有&amp;amp的所有;,这可以扩展到其他转义字符

【讨论】:

  • 如果我尝试使用sep = "(?&lt;!&amp;[a-z]*);" 修改它,那么我会收到错误消息。但喜欢这个主意……
猜你喜欢
  • 2022-10-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-17
  • 2017-05-02
  • 2018-02-03
  • 1970-01-01
  • 2018-05-27
相关资源
最近更新 更多