在pandas中提取包含多行和多列的JSON字符串列的部分

Posted

技术标签:

【中文标题】在pandas中提取包含多行和多列的JSON字符串列的部分【英文标题】:Extracting portions of JSON string column containing multiple rows and columns in pandas 【发布时间】:2019-12-03 03:34:06 【问题描述】:

我有一个数据框,其中 parameters 列是 JSON 并且包含多个实际行和列:

input_data = pandas.DataFrame('id':['0001','0002','0003'],
                               'parameters':["'product':['book','cat','fish'],'person':['me','you']",
                                             "''product':['book','cat'],'person':['me','you','us']'",
                                             "''product':['apple','snake','rabbit','octopus'],'person':['them','you','us','we','they']'"])

...我想从中提取以下数据框:

product_data = pandas.DataFrame('id':['0001','0001','0001','0002','0002','0003','0003','0003','0003'],
                                'product':['book','cat','fish','book','cat','apple','snake','rabbit','octopus'])


person_data = pandas.DataFrame('id':['0001','0001','0002','0002','0002','0003','0003','0003','0003','0003'],
                                'person':['me','you','me','you','us','them','you','us','we','they'])

以下是我如何使用正则表达式来实现目标。我怀疑这是最好的方法,但它就是这样:

for i in input_data.id.tolist():
    s = ''.join(input_data[input_data.id == i]['parameters'])
    product_string = re.search(r"product':(.*?),'person", str(s)).group(1)
    product_data = pandas.DataFrame(product_string[1:-1].split(','))
    person_string = re.search(r"person':(.*?)", str(s)).group(1)
    person_data = pandas.DataFrame(person_string[1:-1].split(','))
    print("........")
    print(product_data)
    print("........")
    print(person_data)

我想学习一种更快、更优雅或有益健康的解决方案,它可能会捕捉到意想不到的细微差别。

【问题讨论】:

如果你说 "parameters 是一个 JSON 字符串列,包含 pandas 中的多行和多列";我编辑了这个并标记了json。在 pandas 中提取/解析 JSON 存在大量问题。真的,您应该从输入 JSON 上的 read_json 开始,而不是 read_csv,以避免不得不手动提取这些东西。 (你能告诉我们你的 JSON 输入文件的 sn-p 吗?没有那个链接这个问题不是MCVE) Loading a file with more than one line of JSON into Pandas的可能重复 重复如Loading a file with more than one line of JSON into Pandas, this。 this 和 many others 请阅读read_json doc 【参考方案1】:

首先,使用str.get访问器设置您的产品和人员

input_data['products'] = input_data.parameters.str.get('product')

现在,对于pandas >= 0.25.0,您可以使用explode 方法

input_data.explode('products')

熊猫<= 0.25.0,可以参考to this thread


我假设您的数据框中有字典,而不是您在此处公开的 字符串

如果你有字符串,你可能总是

import ast
input_data.parameters.apply(ast.literal_eval)

使它们成为真正的字典。

【讨论】:

input_data[['id','products']].explode('products') input_data['products'] = input_data.parameters.str.get('product') 创建每个字段为“nan”的列。这是预期的吗? input_data.parameters.apply(ast.literal_eval) 产生无效的语法错误 读取 JSON 是 read_json 的工作;推荐ast.literal_eval 完全是矫枉过正。 OP 一开始就不应该通过read_csv(或其他)读取损坏的 JSON。【参考方案2】:

鉴于第 2 行和第 3 行中字符串的怪异结构,下面所需的最终输出是一个版本:

input_data = pd.DataFrame('id':['0001','0002','0003'],
                               'parameters':["'product':['book','cat','fish'],'person':['me','you']",
                                             "''product':['book','cat'],'person':['me','you','us']'",
                                             "''product':['apple','snake','rabbit','octopus'],'person':['them','you','us','we','they']'"])

input_data['parameters'] = input_data['parameters'].str.replace("'", '').str.replace("'", '').str.replace("'", '')
input_data = input_data.join(pd.DataFrame(input_data['parameters'].apply(literal_eval).values.tolist()))

获取对象的长度以供以后输入 id 使用

products_len = input_data['product'].apply(len).values
persons_len = input_data['person'].apply(len).values

将每个结果旋转为单独的df

## flatten x into a list of dictionaries
values = input_data['person'].values.flatten().tolist()
flat_results = [item for sublist in values for item in sublist]

## reinsert a and b
person_df = pd.DataFrame(flat_results, columns = ['person'])


## flatten x into a list of dictionaries
values = input_data['product'].values.flatten().tolist()
flat_results = [item for sublist in values for item in sublist]

## reinsert a and b
product_df = pd.DataFrame(flat_results, columns = ['product'])

追加ID:

## person
ids = input_data['id'].repeat(persons_len).reset_index(drop=True)
person_df = person_df.join(ids)

## product
ids = input_data['id'].repeat(products_len).reset_index(drop=True)
product_df = product_df.join(ids)

结果

person_df
Out[57]: 
  person    id
0     me  0001
1    you  0001
2     me  0002
3    you  0002
4     us  0002
5   them  0003
6    you  0003
7     us  0003
8     we  0003
9   they  0003

product_df
Out[58]: 
   product    id
0     book  0001
1      cat  0001
2     fish  0001
3     book  0002
4      cat  0002
5    apple  0003
6    snake  0003
7   rabbit  0003
8  octopus  0003

【讨论】:

以上是关于在pandas中提取包含多行和多列的JSON字符串列的部分的主要内容,如果未能解决你的问题,请参考以下文章

R问题-如何在多列中选择包含某些字符串的多行?

pandas.DataFrame设置某一行为表头(列索引),设置某一列为行索引,按索引取多行多列

Pandas HDFStore 从内存中卸载数据帧

Python pandas str.extract 从多列

C# 多行多列电子邮件阅读器提取器

在多列的单行中显示多行数据