Python数据处理基础题:标注数据整理
©️数据STUDIO转载|作者: 小小明-代码实体 来源:https://xxmdmst.blog.csdn.net/
需求
背景:
有一张图片, 其上用矩形框标注出数目不定的若干对象. 每个对象有若干属性, 每个属性值为预定的值之一. 要求解析输入数据, 适配成人和程序方便阅读的csv格式, 打印或保存结果.
输入:
输入数据有两个, assignment描述的是标注需求, annotations描述的是标注结果.
输入数据示例如下:
assignment_sample = { # assignment 顶层为python字典 'type': 'rectangle', # 标注对象工具类型, 题目中只有矩形框一种, 可忽略 'properties': [{ # 要求标注对象的属性. 数组, 其中每个字典描述一个属性, 数目不定 'id': 1, # 此属性项的唯一id 'name': '对象类型', # 此属性项的名称 'items': ['行人', '车'], # 属性值备选项. 对应annotations中的属性值为其中之一. }],}annotations_sample = [{ # 标注结果, 数组, 其中每个元素描述一个标注对象. 图里画了多少框, 就有多少个 'object_id': 1, # 一张图中标注对象的唯一id 'rectangle': { # 题目只有矩形框 'x1': 100, # 框的坐标, 整数. (x1, y1)是框的左上角点, (x2, y2)是框的右下角点. (图片左上角坐标为(0, 0)) 'y1': 10, 'x2': 201, 'y2': 250, }, 'properties': [{ # 每项表示一个属性. 每个属性一定有值, 所以其长度等于assignment中properties的长度 'property_id': 1, # 对应assignment['properties']中的'id', 表示此项是哪个属性项. 'value': '行人', # 标注的属性值 }]}]
输出:
csv格式, 每行代表一个对象, 要求输出每个对象的object_id和属性值,第一行为列头, 第一个字段是object_id, 余下每个字段是每个属性的name (如示例中的"对象类型")
下面每个对象顺序无要求, object_id对应正确即可,直接print出结果或保存为文件均可。
上面简单示例的输出结果应为:
object\_id,对象类型 1,行人
提示: 用python自带的csv.DictWriter. 可参考官方文档: https://docs.python.org/3/library/csv.html (用手动拼接字符串的方式生成结构化数据是巨大的减分项)
进阶需求, 可任选:
1. 输出结果中添加一个字段, 表示框的面积,例如:
object_id,对象类型,面积1,行人,3000
2. 额外打印出每个"对象类型"的框的个数统计, 格式任意,例如:
object_id,对象类型,面积,个数1,行人,3000,1
数据工程师测试题.py
中待完整的代码:
def convert_to_csv(assignment, annotations): # 请补全此函数 raise NotImplementedError# 程序从这里开始执行if __name__ == '__main__': # 输入数据不要改 assignment = { 'type': 'rectangle', 'properties': [{ 'id': 1, 'name': '对象类型', 'items': ['小汽车', '大汽车', '人', '自行车'], }, { 'id': 2, 'name': '是否清晰', 'items': ['是', '否'], }, { 'id': 3, 'name': '是否完整', 'items': ['完整', '不完整'], }], } annotations = [{ 'object_id': 100, 'rectangle': { 'x1': 100, 'y1': 100, 'x2': 150, 'y2': 150, }, 'properties': [{ 'property_id': 1, 'value': '自行车', }, { 'property_id': 2, 'value': '是', }, { 'property_id': 3, 'value': '完整', }] }, { 'object_id': 101, 'rectangle': { 'x1': 200, 'y1': 100, 'x2': 450, 'y2': 150, }, 'properties': [{ 'property_id': 1, 'value': '大汽车', }, { 'property_id': 2, 'value': '是', }, { 'property_id': 3, 'value': '不完整', }] }, { 'object_id': 102, 'rectangle': { 'x1': 100, 'y1': 150, 'x2': 120, 'y2': 150, }, 'properties': [{ 'property_id': 3, 'value': '完整', }, { 'property_id': 1, 'value': '大汽车', }, { 'property_id': 2, 'value': '否', }] }, { 'object_id': 103, 'rectangle': { 'x1': 300, 'y1': 100, 'x2': 400, 'y2': 200, }, 'properties': [{ 'property_id': 3, 'value': '完整', }, { 'property_id': 1, 'value': '人', }, { 'property_id': 2, 'value': '是', }] }] convert_to_csv(assignment, annotations)
解题
实现函数为:
from collections import Counterimport csvfrom io import StringIOdef convert_to_csv(assignment, annotations): # 请补全此函数 properties = {row["id"]: row["name"] for row in assignment["properties"]} data = [] c = Counter() for annotation in annotations: row = {"object_id": annotation["object_id"]} for propertie in annotation["properties"]: row[properties[propertie["property_id"]]] = propertie["value"] p = annotation["rectangle"] row["面积"] = (p["x2"]-p["x1"])*(p["y2"]-p["y1"]) c[row["对象类型"]] += 1 data.append(row) for row in data: row["个数"] = c[row["对象类型"]] csvfile = StringIO() writer = csv.DictWriter(csvfile, fieldnames=data[0].keys()) writer.writeheader() for row in data: writer.writerow(row) csvfile.seek(0) print(csvfile.read())
结果
object_id,对象类型,是否清晰,是否完整,面积,个数 100,自行车,是,完整,2500,1 101,大汽车,是,不完整,12500,2 102,大汽车,否,完整,0,2 103,人,是,完整,10000,1
🏴☠️宝藏级🏴☠️ 原创公众号『 数据STUDIO 』内容超级硬核。公众号以Python为核心语言,垂直于数据科学领域,包括 可戳 👉 Python | MySQL | 数据分析 | 数据可视化 | 机器学习与数据挖掘 | 爬虫 等,从入门到进阶!
长按👇关注- 数据STUDIO -设为星标,干货速递