【问题标题】:Parsing a JSON string enclosed with quotation marks from a CSV using Pandas使用 Pandas 从 CSV 解析用引号括起来的 JSON 字符串
【发布时间】:2018-09-08 07:28:27
【问题描述】:

类似于this question,但我的 CSV 格式略有不同。这是一个例子:

id,employee,details,createdAt  
1,John,"{"Country":"USA","Salary":5000,"Review":null}","2018-09-01"  
2,Sarah,"{"Country":"Australia", "Salary":6000,"Review":"Hardworking"}","2018-09-05"

我认为 JSON 列开头的双引号可能导致了一些错误。使用df = pandas.read_csv('file.csv'),这是我得到的数据框:

id  employee                details    createdAt              Unnamed: 1  Unnamed: 2 
 1      John        {Country":"USA"  Salary:5000           Review:null}"  2018-09-01 
 2     Sarah  {Country":"Australia"  Salary:6000  Review:"Hardworking"}"  2018-09-05

我想要的输出:

id  employee                                                       details   createdAt
 1      John                 {"Country":"USA","Salary":5000,"Review":null}  2018-09-01 
 2     Sarah  {"Country":"Australia","Salary":6000,"Review":"Hardworking"}  2018-09-05 

我尝试添加 quotechar='"' 作为参数,但它仍然没有给我想要的结果。有没有办法告诉 pandas 忽略 json 值周围的第一个和最后一个引号?

【问题讨论】:

  • 问题不在于引号,而在于逗号,而读取csv时,所有以逗号分隔的条目都被视为下一列
  • @Gahan CSV 中的单列可以包含逗号。问题可能是字符串上的封闭",导致逗号被解释为新列而不是字典结构的一部分
  • @roganjosh ,我试过了,结构太负责了,因为引号括起来 "{" 然后 Country 没有引号,然后 ":" 在引号中,然后 USA" 和逗号遇到了哪个将其解释为下一列值
  • 我怀疑它只能用正则表达式来解决,这让我无法帮助抱歉:/
  • 与其尝试解析它,不如首先不要混合使用两种交互不良的元格式(CSV、JSON)来写入数据。只需一直使用 JSON 作为默认值。如果你必须使用这个,你需要转义引号。

标签: python json pandas


【解决方案1】:

作为替代方法,您可以手动读取文件,正确解析每一行并使用生成的 data 来构建数据框。这通过将行向前和向后拆分以获得无问题的列,然后取出剩余部分来工作:

import pandas as pd

data = []

with open("e1.csv") as f_input:
    for row in f_input:
        row = row.strip()
        split = row.split(',', 2)
        rsplit = [cell.strip('"') for cell in split[-1].rsplit(',', 1)]
        data.append(split[0:2] + rsplit)

df = pd.DataFrame(data[1:], columns=data[0])
print(df)

这会将您的数据显示为:

  id employee                                            details   createdAt
0  1     John      {"Country":"USA","Salary":5000,"Review":null}  2018-09-01
1  2    Sarah  {"Country":"Australia", "Salary":6000,"Review"...  2018-09-05

【讨论】:

  • 是的,我正在做类似的事情:将文件作为原始文本读取,然后进行修改,以便熊猫可以读取 JSON 格式。谢谢!
【解决方案2】:

我已经复制了你的文件 与

   df = pd.read_csv('e1.csv', index_col=None )

print (df)

输出

     id    emp                                            details      createdat
0   1   john    "{"Country":"USA","Salary":5000,"Review":null}"  "2018-09-01" 
1   2  sarah  "{"Country":"Australia", "Salary":6000,"Review...   "2018-09-05"

【讨论】:

  • 您能否指定您还做了哪些技巧,尝试了您的解决方案并引发异常:ParserError: Error tokenizing data. C error: Expected 4 fields in line 2, saw 6
  • 嗨,我尝试使用header=None,但结果仍然相同。
  • index_col 默认为None,因此您的上述解决方案等同于 OP 已经尝试过的解决方案。
【解决方案3】:

我认为通过将正则表达式传递给sep=r',"|",|(?<=\d),' 以及可能的其他一些参数组合有更好的方法。我还没有完全弄清楚。

这是一个不太理想的选择:

df = pd.read_csv('s083838383.csv', sep='@#$%^', engine='python')
header = df.columns[0]
print(df)

为什么是sep='@#$%^'?这只是垃圾,允许您读取没有 sep 字符的文件。它可以是任何随机字符,仅用作将数据导入df 对象以供使用的一种方式。

df 看起来像这样:

                       id,employee,details,createdAt
0  1,John,"{"Country":"USA","Salary":5000,"Review...
1  2,Sarah,"{"Country":"Australia", "Salary":6000...

然后您可以使用str.extract 应用正则表达式并扩展列:

result = df[header].str.extract(r'(.+),(.+),("\{.+\}"),(.+)',
                                expand=True).applymap(str.strip)

result.columns = header.strip().split(',')
print(result)

result 是:

  id employee                                            details     createdAt
0  1     John    "{"Country":"USA","Salary":5000,"Review":null}"  "2018-09-01"
1  2    Sarah  "{"Country":"Australia", "Salary":6000,"Review...  "2018-09-05"

如果您需要从 details 字符串值中去掉开头和结尾的引号,您可以这样做:

result['details'] = result['details'].str.strip('"')

如果details 对象项需要是dicts 而不是字符串,您可以这样做:

from json import loads
result['details'] = result['details'].apply(loads)

【讨论】:

    猜你喜欢
    • 2014-01-07
    • 2017-07-26
    • 2022-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-10
    • 1970-01-01
    相关资源
    最近更新 更多