You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何展开含单层冗余键的嵌套字典提取AIS数据的MessageID

展开AIS嵌套字典提取MessageID字段

问题背景

我在pandas数据帧dfAIS中存储了AIS自动识别系统的嵌套字典数据,结构如下:

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]

核心数据在Message列,每个元素是仅含一个键值对的字典:键(如ShipStaticData、MultiSlotBinaryMessage)可视为消息类型,我称其为一级字典;实际有效数据在该键对应的二级字典中,包含AisVersion、ApplicationID、Cog、MessageID等字段。

由于二级字典自带MessageID用于标识消息类型,且数据帧已有MessageType列存储与一级字典键相同的标签,因此一级字典的键属于冗余信息,无需保留。我想展开嵌套字典直接访问MessageID,但因不同消息类型的嵌套路径不一致(如Message.ShipStaticData.MessageID和Message.MultiSlotBinaryMessage.MessageID),无法直接用json_normalize;尝试用dfAIS.Message.apply(dict.items)后,得到的是嵌套元组序列,冗余的消息类型键仍存在:

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

解决方案

方案1:处理已加载的DataFrame

提取二级字典并提取MessageID

先把Message列的每个元素转换为二级字典(跳过冗余的一级键),再提取MessageID:

# 提取二级字典:取每个字典的第一个值
dfAIS['MessageContent'] = dfAIS['Message'].apply(lambda x: next(iter(x.values())))

# 提取MessageID,空字典或无该字段时返回NaN
dfAIS['MessageID'] = dfAIS['MessageContent'].apply(lambda x: x.get('MessageID', pd.NA))

如果需要将二级字典的所有字段展开到数据帧中,可以用json_normalize:

message_df = pd.json_normalize(dfAIS['Message'].apply(lambda x: next(iter(x.values()))))
# 合并回原数据帧
dfAIS = pd.concat([dfAIS.drop(columns=['Message']), message_df], axis=1)

高效批量处理(避免逐行apply)

针对13万行的大数据量,用列表推导式提升处理效率:

# 提取所有二级字典
message_contents = [next(iter(msg.values())) for msg in dfAIS['Message']]
# 转成数据帧
message_df = pd.DataFrame(message_contents)
# 合并回原数据帧
dfAIS = pd.concat([dfAIS.drop(columns=['Message']), message_df], axis=1)

方案2:从JSONL源文件读取时直接处理

如果可以重新加载数据,可在读取阶段跳过冗余的一级键,减少后续处理步骤:

import pandas as pd

# 读取JSONL文件
df = pd.read_json('ais_data.jsonl', lines=True)
# 替换Message列为二级字典内容
df['Message'] = df['Message'].apply(lambda x: next(iter(x.values())))
# 展开所有字段
final_df = pd.concat([df.drop(columns=['Message']), pd.json_normalize(df['Message'])], axis=1)

也可以在读取时用converters参数直接处理:

df = pd.read_json(
    'ais_data.jsonl',
    lines=True,
    converters={'Message': lambda x: next(iter(x.values()))}
)
final_df = pd.concat([df.drop(columns=['Message']), pd.json_normalize(df['Message'])], axis=1)

附言解答

术语表述建议

可以将一级字典的键称为消息类型标识键,对应的二级字典称为消息内容字典,能清晰区分两者,避免混淆。

3行JSONL样本

{"Message": {"ShipStaticData": {"AisVersion": 0, "CallSign": "GDNB   ", "Destination": "AVONMOUTH DREDGING  ", "Dimension": {"A": 30, "B": 5, "C": 7, "D": 3}, "Dte": false, "Eta": {"Day": 0, "Hour": 24, "Minute": 60, "Month": 0}, "FixType": 1, "ImoNumber": 702864, "MaximumStaticDraught": 14, "MessageID": 5, "Name": "MALAGO              ", "RepeatIndicator": 0, "Spare": false, "Type": 33, "UserID": 235065329, "Valid": true}}, "MessageType": "ShipStaticData", "MetaData": {"MMSI": 235065329, "MMSI_String": 235065329, "ShipName": "MALAGO              ", "latitude": 51.50296166666667, "longitude": -2.707621666666667, "time_utc": "2024-04-15 23:00:24.874950587 +0000 UTC"}}
{"Message": {"PositionReport": {"Cog": 226.1, "CommunicationState": 59916, "Latitude": 33.74614666666667, "Longitude": -118.22303833333334, "MessageID": 1, "NavigationalStatus": 0, "PositionAccuracy": false, "Raim": false, "RateOfTurn": 0, "RepeatIndicator": 0, "Sog": 1.1, "Spare": 0, "SpecialManoeuvreIndicator": 0, "Timestamp": 24, "TrueHeading": 11, "UserID": 367693690, "Valid": true}}, "MessageType": "PositionReport", "MetaData": {"MMSI": 367693690, "MMSI_String": 367693690, "ShipName": "KELLY C             ", "latitude": 33.74614666666667, "longitude": -118.22303833333334, "time_utc": "2024-04-15 23:00:24.875182234 +0000 UTC"}}
{"Message": {"Interrogation": {"MessageID": 15, "RepeatIndicator": 3, "Spare": 0, "Station1Msg1": {"MessageID": 316004037, "SlotOffset": 0, "StationID": 316004037, "Valid": true}, "Station1Msg2": {"MessageID": 0, "SlotOffset": 0, "Spare": 0, "Valid": false}, "Station2": {"MessageID": 0, "SlotOffset": 0, "Spare1": 0, "Spare2": 0, "StationID": 0, "Valid": false}, "UserID": 3669987, "Valid": true}}, "MessageType": "Interrogation", "MetaData": {"MMSI": 3669987, "MMSI_String": 3669987, "ShipName": "", "latitude": 47.548895, "longitude": -122.78526333333333, "time_utc": "2024-04-15 23:00:24.875383071 +0000 UTC"}}

内容的提问来源于stack exchange,提问作者user2153235

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 19:20:11