【问题标题】:Convert JSON column in dataframe to simple array of values将数据框中的 JSON 列转换为简单的值数组
【发布时间】:2019-04-14 18:16:25
【问题描述】:

我正在尝试将 bbox(边界框)列中的 JSON 转换为 Jupyter 笔记本中 Python 中的 DL 项目的简单值数组。

可能的标签有以下类别:[玻璃、纸板、垃圾、金属、纸张]。

[{"left":191,"top":70,"width":183,"height":311,"label":"glass"}]

TO

([191 70 183 311], 0)

我正在寻求帮助,将 JSON 对象中的 bbox 列转换为包含所有图像名称和相关 bbox 的单个 CSV。

更新

当前列是一个系列,所以每当我尝试在该列上应用 JSON 操作时,我都会不断收到“TypeError:JSON 对象必须是 str、字节或 bytearray,而不是‘系列’”。到目前为止,我已经尝试将列转换为 JSON 对象,然后从键中提取值。

BB_CSV

【问题讨论】:

  • 0 代表什么?
  • @W-B 0 是代表标签的数字。 1 是纸板,2 是垃圾,依此类推
  • @cleme001,到目前为止,您是否尝试过任何方法来实现它,这也将提供真正需要的线索。

标签: python json pandas jupyter-notebook


【解决方案1】:

您需要使用 JSON 解码器:https://docs.python.org/3/library/json.html

import json
li = json.loads('''[{"left":191,"top":70,"width":183,"height":311,"label":"glass"}]''')
d = dictionary = li[0]
result = ([d[key] for key in "left top width height".split()], 0)
print(result)

编辑:

如果你想从字典中提取值的操作映射到列表的所有元素,你可以这样做:

extracted = []
for element in li:
    result = ([element[key] for key in "left top width height".split()], 0)
    extracted.append(result)

# print(extracted)
print(extracted[:10])
# `[:10]` is there to limit the number of item displayed to 10

同样,根据我的评论,如果您不想在列表中提取的数字之间使用逗号,您可以使用:

without_comma = []
for element, zero in extracted:
    result_string = "([{}], 0)".format(" ".join([str(value) for value in element]))
    without_comma.append(result_string)

【讨论】:

  • 如果要检查标签的值是否正确,可以添加assert dictionary["label"] in "glass cardboard trash metal paper".split(),如果不正确则报错。
  • 如果您不想在 bbox 中的值之间使用逗号,请使用 print("([{}], 0)".format(" ".join(str(d[key]) for key in "left top width height".split())))
  • 所以我设法让它适用于我的用例,稍微调整了你的代码,但由于 .split 只对 json 对象的第一个实例执行此操作,所以我拥有的带有多个注释的图片不会' t得到正确转换。例如[{"left":191,"top":70,"width":183,"height":311,"label":"glass"}, {"left":200,"top":60,"width ":132,"height":318,"label":"glass"}]
【解决方案2】:

看起来bbox 列的每一行都在list 内包含一个dictionary。我试图复制您的问题如下。 编辑:澄清以下解决方案假定您所指的“JSON 对象”表示为包含单个字典的 list,这就是您的示例所显示的内容和截图。

# Create empty sample DataFrame with one row
df = pd.DataFrame([None],columns=['bbox'])

# Assign your sample item to the first row
df['bbox'][0] = [{"left":191,"top":70,"width":183,"height":311,"label":"glass"}]

现在,简单解压行:

df['bbox_unpacked'] = df['bbox'].map(lambda x: x[0].values())

这将为您提供一个包含 5 个项目的 tuple 的新列。

如果您想更进一步并应用您的标签,您可能需要创建一个字典来包含您的标签逻辑。根据您在 cmets 中给出的示例,我已经完成了:

labels = {
    'cardboard': 1,
    'trash': 2,
    'glass': 3
}

如果您想要一个不编写自己的函数的单行解决方案,这应该会得到您想要的布局。

df['bbox_unpacked'] = df['bbox'].map(lambda x: (list(x[0].values())[:4],labels.get(list(x[0].values())[-1])))

更易读的解决方案是使用.apply() 方法定义您自己的函数。 编辑: 由于您的 JSON 对象看起来像 str 存储在您的 DataFrame 行中,因此我添加了 json.loads(row) 以在检索键之前先处理字符串。您需要import json 才能运行。

import json    

def unpack_bbox(row, labels):

    # load the string into a JSON object (in this
    # case a list of length one containing the dictionary;
    # index the list to its first item [0] and use the .values()
    # dictionary method to access the values only 

    keys = list(json.loads(row)[0].values())

    bbox_values = keys[:4]
    bbox_label = keys[-1]

    label_value = labels.get(bbox_label)

    return bbox_values, label_value

df['bbox_unpacked'] = df['bbox'].apply(unpack_bbox,args=(labels,))

【讨论】:

  • 由于某种原因,当我执行 BB_CSV['bbox'][0] 时,我得到了多行 - 在帖子中添加了一张图片。
  • @cleme001 df['bbox'][0] sn-p 只是为了展示我如何将您的示例列表分配给示例DataFrame 的一行以复制您的问题。您是否尝试过 BB_CSV['bbox'].map(lambda x: x[0].values()) 解压缩行?
  • 问题似乎是它自己的行不是字符串而是 numpyndarray 所以我收到了这个错误。 BB_CSV['bbox'][0].values() ------------------------------------------------- -------------------------------------- TypeError Traceback (最近一次调用最后一次) in () ----> 1 BB_CSV['bbox'][0].values() TypeError: 'numpy.ndarray' object is not callable
  • 此外,如果您查看我附在原始帖子中的图片,您会发现,当我什至尝试查看单行时,我会得到 5 个不同的东西,而不仅仅是该行的值。
  • @cleme001 您的 DataFrame 的索引中是否有重复值?你可以试试df.reset_index(drop=True, inplace=False) 再试一次吗?
猜你喜欢
  • 2021-03-01
  • 2016-06-25
  • 1970-01-01
  • 1970-01-01
  • 2021-04-06
  • 2021-08-12
  • 1970-01-01
  • 1970-01-01
  • 2020-05-15
相关资源
最近更新 更多