python - 熊猫读取 csv 忽略 " 字符
问题描述
我有一个用字符分号(;)分隔的 CSV 数据框。我的数据框中的几列是 JSON 类型,我想在后面的部分将它们转换为 python dict。
CSV file <tmp.csv>:
7.384906;7.3849072;2;0.2708226296521021;0;0;0;;
9.05233;9.05192;5;0.5523690040041611;1;0;0;"{\"EMAIL_SENT\": 1}";"{\"-1\": 1}"
3.6593602;3.6593602;2;0.5465436324626254;0;0;0;;
3.5134177;3.5130887;2;0.5692996018584914;0;0;0;;
0.6824124;0.6824124;2;2.9307791611130423;0;0;0;"{\"STAGE_CHANGE\": 1, \"CREATE\": 1}";"{\"-1\": 2}"
当我将此文件读入熊猫时,
>>> df = pd.read_csv("tmp.csv", sep=";", header=None)
>>> df
0 1 2 3 4 5 6 7 8
0 7.384906 7.384907 2 0.270823 0 0 0 NaN NaN
1 9.052330 9.051920 5 0.552369 1 0 0 {\EMAIL_SENT\": 1}" {\-1\": 1}"
2 3.659360 3.659360 2 0.546544 0 0 0 NaN NaN
3 3.513418 3.513089 2 0.569300 0 0 0 NaN NaN
4 0.682412 0.682412 2 2.930779 0 0 0 {\STAGE_CHANGE\": 1, \"CREATE\": 1}" {\-1\": 2}"
如此处所示,我的 JSON 列未正确读取。我在每个 JSON 的开头都缺少字符 "。因此,我无法将其转换为 python dict。
>> df[8].apply(lambda elem: {} if pd.isna(elem) else json.loads(elem))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/opt/anaconda3/envs/forecasting/lib/python3.7/site-packages/pandas/core/series.py", line 3848, in apply
mapped = lib.map_infer(values, f, convert=convert_dtype)
File "pandas/_libs/lib.pyx", line 2329, in pandas._libs.lib.map_infer
File "<stdin>", line 1, in <lambda>
File "/opt/anaconda3/envs/forecasting/lib/python3.7/json/__init__.py", line 348, in loads
return _default_decoder.decode(s)
File "/opt/anaconda3/envs/forecasting/lib/python3.7/json/decoder.py", line 337, in decode
obj, end = self.raw_decode(s, idx=_w(s, 0).end())
File "/opt/anaconda3/envs/forecasting/lib/python3.7/json/decoder.py", line 353, in raw_decode
obj, end = self.scan_once(s, idx)
json.decoder.JSONDecodeError: Expecting property name enclosed in double quotes: line 1 column 2 (char 1)
请让我知道如何解决这个问题。
解决方案
在读取 csv 时不使用引号,然后在将字符串加载到 json 之前去掉前导/尾随双引号。
df = pd.read_csv("tmp.csv", sep=";", header=None, quoting=3)
df[7].apply(lambda elem: {} if pd.isna(elem) else json.loads(elem.strip('"')))
df[8].apply(lambda elem: {} if pd.isna(elem) else json.loads(elem.strip('"')))
结果:
0 1 2 ... 6 7 8
0 7.384906 7.384907 2 ... 0 {} {}
1 9.052330 9.051920 5 ... 0 {'EMAIL_SENT': 1} {'-1': 1}
2 3.659360 3.659360 2 ... 0 {} {}
3 3.513418 3.513089 2 ... 0 {} {}
4 0.682412 0.682412 2 ... 0 {'STAGE_CHANGE': 1, 'CREATE': 1} {'-1': 2}
更新json字符串包含分隔符的情况
我没有通用解决方案,在您的示例中只有一个(相当丑陋的)解决方法。如果您知道 json 字符串在最后一列中,则可以使用保证不在字符串中的分隔符将 csv 作为一列读取,然后将第一列拆分为实际分隔符,将 json 列拆分为实际用双引号括起来的分隔符。从这里您可以像以前一样继续,只有空列
''
而不是NA
.
例子:
df = pd.read_csv('tmp.csv', sep='\n', header=None)[0].str.split(';', 7, expand=True)
df[[7,8]] = df[7].str.split('";"|^;$', expand=True)
df[7] = df[7].apply(lambda elem: {} if elem == '' else json.loads(elem.strip('"').replace('\\"', '"')))
df[8] = df[8].apply(lambda elem: {} if elem == '' else json.loads(elem.strip('"').replace('\\"', '"')))
结果:
0 1 2 3 4 5 6 7 8
0 7.384906 7.3849072 2 0.2708226296521021 0 0 0 {} {}
1 9.05233 9.05192 5 0.5523690040041611 1 0 0 {'EMAIL_SENT': 1} {'-1': 1}
2 3.6593602 3.6593602 2 0.5465436324626254 0 0 0 {} {}
3 3.5134177 3.5130887 2 0.5692996018584914 0 0 0 {} {}
4 0.6824124 0.6824124 2 2.9307791611130423 0 0 0 {'STAGE_CHANGE': 1, 'CREATE; HA': 1} {'-1': 2}
推荐阅读
- flutter - 处理文本字段数据,将其保存在本地文本文件中并随后显示
- r - 如何使用 R 在 t.test 中仅运行比较子集?
- python - 在 Python 中按值比较两个列表
- php - PHP 7.4 中无法捕获弃用警告
- java - 如何从 curl 生成正确的 RestTemplate 用法?
- databricks - 使用 sting 文件路径 (read.csv) 将日期变量插入 Dataframe
- python - 我什么时候应该在 StratifiedKFold 中洗牌
- c# - 如何制作 C# 脚本
- javascript - 如何在以烧瓶为后端的 React js 应用程序中进行会话管理?
- jsf - java.lang.NullPointerException at com.sun.faces.mgbean.ManagedBeanBuilder.getPropertyDescriptor 使用时