我有自动识别系统(AIS)数据作为 pandas 数据框中的嵌套字典。这是一个例子:
dfAIS
Out[18]:
Message ... MetaData
0 {'ShipStaticData': {'AisVersion': 1, 'CallSign... ... {'MMSI': 255814000, 'MMSI_String': 255814000, ...
1 {'MultiSlotBinaryMessage': {'ApplicationID': {... ... {'MMSI': 2276003, 'MMSI_String': 2276003, 'Shi...
2 {'StandardClassBPositionReport': {'AssignedMod... ... {'MMSI': 503760500, 'MMSI_String': 503760500, ...
3 {'PositionReport': {'Cog': 25.2, 'Communicatio... ... {'MMSI': 211648000, 'MMSI_String': 211648000, ...
4 {'StaticDataReport': {'MessageID': 24, 'PartNu... ... {'MMSI': 338467989, 'MMSI_String': 338467989, ...
... ... ...
139625 {'PositionReport': {'Cog': 360, 'Communication... ... {'MMSI': 244730300, 'MMSI_String': 244730300, ...
139626 {'PositionReport': {'Cog': 231.5, 'Communicati... ... {'MMSI': 219025528, 'MMSI_String': 219025528, ...
139627 {'PositionReport': {'Cog': 360, 'Communication... ... {'MMSI': 273252100, 'MMSI_String': 273252100, ...
139628 {'UnknownMessage': {}} ... {'MMSI': 244730043, 'MMSI_String': 244730043, ...
139629 {'ShipStaticData': {'AisVersion': 1, 'CallSign... ... {'MMSI': 211666470, 'MMSI_String': 211666470, ...
[139630 rows x 3 columns]
核心数据位于“消息”栏。其中每个元素都是一个只有 1 个键和 1 个值的字典。如上所示,一个键可能是“ShipStaticData”、“MultiSlotBinaryMessage”等,我们可以将其视为消息类型。我们将这个字典称为一级字典。
一级字典是一个无关的映射层,因为所需的数据驻留在相应的值中,而相应的值本身就是一个完整的字典。我们将后者称为二级词典。如上所示,二级字典中的字段可以是“AisVersion”、“ApplicationID”、“Cog”等。here指定有效字段。
我不需要 1 级字典的键,因为 2 级字典包含一个 MessageID 字段,该字段更明确地映射到消息类型。此外,数据框
dfAIS
还有一个上面未显示的MessageType列,它包含与1级字典中唯一键相同的标签。
我一直在自学数据帧操作,使用 apply 从 2 级字典中提取 MessageID。我还发现 json_normalize 是一个不错的选择。不幸的是,在嵌套字典中,它要求公共字段的分层路径具有相同的路径组件。我无法将它用于上述场景,因为
Message.ShipStaticData.MessageID
与 Message.MultiSlotBinaryMessage.MessageID
是不同的路径。在这两条路径中,3 个路径组件中的第 2 个是我希望不存在的无关映射层。
如何取消嵌套嵌套字典以便可以访问 MessageID 字段?
我尝试使用
pandas.DataFrame.apply
将字典方法items()
应用于dfAIS
列Message
的元素。它产生一系列嵌套元组并且
无关的消息类型键仍然存在:
df = dfAIS.Message.apply(dict.items)
0 ((ShipStaticData, {'AisVersion': 1, 'CallSign'...
1 ((MultiSlotBinaryMessage, {'ApplicationID': {'...
2 ((StandardClassBPositionReport, {'AssignedMode...
3 ((PositionReport, {'Cog': 25.2, 'Communication...
4 ((StaticDataReport, {'MessageID': 24, 'PartNum...
139625 ((PositionReport, {'Cog': 360, 'CommunicationS...
139626 ((PositionReport, {'Cog': 231.5, 'Communicatio...
139627 ((PositionReport, {'Cog': 360, 'CommunicationS...
139628 ((UnknownMessage, {}))
139629 ((ShipStaticData, {'AisVersion': 1, 'CallSign'...
Name: Message, Length: 139630, dtype: object
P.S. 我也在纠结如何引用“ShipStaticData”、“MultiSlotBinaryMessage”等标签。它们是 1 级字典的键。谈论 1 级键所采用的“值”本来很方便,但“值”已经指的是键映射到的事物。我们可以非常仔细地说,后者是与键关联的值,或者是键的值,但这仍然会造成混淆。是否有更清晰(且简洁)的方式来引用“ShipStaticData”、“MultiSlotBinaryMessage”等? 人们经常忘记 JSON 只是 Python 中的普通数据结构,并且他们可以在初始化数据帧之前进行操作。并非所有事情都需要由 pandas 处理。
with open("data.json") as fp:
data = json.load(fp)
messages = [
value
for message in data["Message"]
for _, value in message.items()
]
df = pd.DataFrame(messages)