使用Pandas从CSV解析带引号的JSON字符串

时间:2018-09-08 07:28:28

标签: python json pandas

类似于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='"'作为参数,但仍然没有得到想要的结果。有没有办法告诉熊猫忽略json值的第一个和最后一个引号?

3 个答案:

答案 0 :(得分:0)

我已转载您的文件 与

   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"

答案 1 :(得分:0)

我认为通过将正则表达式传递给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对象项需要是dict而不是字符串,则可以执行以下操作:

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

答案 2 :(得分:0)

作为一种替代方法,您可以手动读取文件,正确解析每一行,然后使用生成的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