手把手教你完成半结构化数据的处理

本文介绍如何使用Python将Excel中存储的JSON数据转换为结构化数据框,并通过两个案例演示数据处理流程,包括数据拆解、聚合操作等。
前言

      现在越来越多的数据以json的格式进行存储,例如通过网络爬虫时,那些异步存储的数据往往都是json类型的;再如企业数据库中的日志数据,也会以json的格式存放。前不久,一位网友就碰到了这个问题,手中Excel存储的数据并不是标准化的结构数据,而是以json格式存储在Excel的每个单元格。那今天我们就来聊聊如何利用Python将半结构化的json数据转换成结构化数据

简单的json格式

      其实json的格式与Python中的字典非常类似,数据放在大括号({})内,每一个元素都是键值对,元素之间以逗号隔开。我们都知道,在Python中,是可以将一个字典对象转换成数据框的,接下来我们就通过一个简单的例子慢慢进入复杂的环境。

# 加载第三方包
import pandas as pd # 数据处理包
import numpy as np # 数值计算包
import json # json文件转换包

# 一个简单的json格式字符串
string1 = '{"name":"Sim","gender":"Male","age":28,"province":"江苏"}'
string2 = '{"name":"Lily","gender":"Feale","age":25,"province":"湖北"}'

# 查看数据类型
type(string)

# 将json格式转换为字典
dict1 = json.loads(string1) dict2 = json.loads(string2) type(dict1)

      上面构造的json数据实际上是字典型的字符串,可以直接通过json包中的loads函数完成由字符型到字典型的转化。那如何根据这两个字典,组装成一个2行3列的数据框呢?只需借助于pandas模块中的DataFrame函数即可:

# 将字典数据转换为数据框
pd.DataFrame([dict1,dict2])



这里需要注意的是,上面的字典,是一个键仅对应一个值的情况,如果直接将dict1传递给DataFrame函数是会出错的,除非你指定索引值。所以,当你有两个及以上的这种字典时,你是可以传递给DataFrame函数的,但必须以可迭代的形式(如列表、元组、序列等)。还有一种字典,是一个键对应多个值,如果是这样的字典,就可以直接将字典扔给DataFrame函数形成数据框了:

string =  '{"name":["Sim","Lily"],"gender":["Male","Feale"],\
            "age":[28,25],"province":["江苏","湖北"]}'

# 转换为数据框            
pd.DataFrame(json.loads(string))


尽管这样完成了一个字典到数据框的转换,但千万注意,如果一个字典的键包含多个值,那一定要保证所有键对应的值个数一致!OK,了解了这个基础知识点后,我们来两个案例,加深一下对知识点的理解。

经典案例一

      先来看一下Excel表中存储的数据格式,现在的问题是,如何将表中UserBasic一列拆解出来,即所有键值对转换成变量名和观测值。


data1 = pd.read_excel(r'C:\Users\Administrator\Desktop\data1.xlsx')
data1.head()

data1.UserBasic[0]



从上面的反馈结果来看,表中UserBasic字段的单元格存储的json字符串都是一个键仅对应一个值,这跟上面介绍的string1和string2是一致的,故如果需要转换成数据框的话,需要将这些转换的字典存放到列表中。具体操作如下:

# UserBasic列中的信息拆分到各个变量中
basic = []for i in data1.UserBasic:    basic.append(json.loads(i)) UserBasic = pd.DataFrame(basic) UserBasic.head()



上面通过循环的方式将UserBasic字段的每一行解析成字典,并保存到列表中,最后通过DataFrame函数完成数据框的转换。接下来需要将拆分出来的这列,与原始表中的Id变量,Mobile变量整合到一起

# 数据整合到一起
final_data = pd.concat([data1[['Id','Mobile']],UserBasic], axis = 1) final_data.head()



效果呈现还是蛮好的,但是有一点不好的是,通过for循环来完成毕竟不是高效的,如果数据量特别大,上百万行的话,那就得循环执行上百万次,会耗很多时间。这里我们借助于apply方法,避免显式的循环:

# 避免循环的方式
trans_data = pd.DataFrame(data1.UserBasic.apply(json.loads))
# 数据整合到一起
final_data = pd.concat([data1[['Id','Mobile']],trans_data], axis = 1)
经典案例二

      我们接着看第二个例子,原始数据如下图所示,现在的问题是解析字段CellBehaviorData的同时,还要做一次聚合操作(每个用户ID近3个月的消费平均水平)。


# 读取数据
data2 = pd.read_excel(r'C:\Users\Administrator\Desktop\data2.xlsx')

# 查看字段CellBehaviorData第一行的信息
data2.CellBehaviorData[0]



细心的你一定发现了个问题,这个字符串的起始和结尾并不是大括号({}),而是中括号([]),故接下来要做的第一件事就是去除这两个中括号;另一方面,behavior键对应的值是列表,而且列表中还有多个相同的键,如sms_cnt、cell_phone_num等。这样的json最后形成的数据框一定是多行的,即表中一个单元格会就可以转换成多行的数据框。不妨,我们先来看一下变量CellBehaviorData第一行形成是数据框张啥样:

# 通过切片的方式去除首尾的中括号
s = data2.CellBehaviorData[0][1:-1]
# 将字符串转换成字典,并取出behavior键
d = json.loads(s)['behavior']
# 将字典转换为数据框
df = pd.DataFrame(d) df



这就是一行观测产生的多行数据框,现在的问题是如何将多行的数据框与每一个Id配对上。我们发现字典中除了behavior键,还有phone_num键,而且该键的值是唯一的,正好与上面数据框的cell_phone_num变量匹配。所以,待会做数据关联的时候,就使用phone_num变量和cell_phone_num变量。

# 取出phone_num
phone_num = [i['phone_num'] for i in data2.CellBehaviorData.str[1:-1].apply(json.loads)]

# 取出CellBehaviorData字段,并解析为数据框
df = pd.concat([pd.DataFrame(j) for j in [i['behavior'] for i in data2.CellBehaviorData.str[1:-1].apply(json.loads)]])# 将Id与手机号捆绑user = pd.concat([pd.Series(phone_num,name = 'phone_num'), data2.Id], axis = 1)

# 以手机号作为数据的关联关联
final_data = pd.merge(df, user, left_on = 'cell_phone_num', right_on='phone_num') final_data.head()

# 查看数据类型
final_data.dtypes



为了速度的提升,上面使用了apply技术和列表解析式的技巧将json数据拆解成数据框,同时,发现除Id变量的其他变量类型都是字符串型,需要对数值变量进行转换,因为接下来还要做聚合操作:

# 挑选需要转换类型的变量名称
vars = ['call_cnt','call_in_cnt','call_in_time','call_out_cnt','call_out_time','net_flow','sms_cnt','total_amount']

# 对以上变量进行数据类型转换
df_convert = final_data[vars].apply(lambda x: x.astype('float'))

# 从新完成数据合并
final_data2 = pd.concat([df_convert, final_data.loc[:,~final_data.columns.isin(vars)]], axis = 1)

# 对每个id计算近三个月的平均指标值
stats = final_data2.loc[final_data2.cell_mth.isin(['2017-08','2017-07','2017-06']),:].groupby('Id').aggregate(np.mean) stats


 

大功告成,这种类型的数据我们就可以游刃有余的完成转换。但如果CellBehaviorData字段不含有phone_num(键)变量的话如何实现数据关联呢?这里把解决方案的代码呈现出来:

# 构造空列表,存放CellBehaviorData变量每一行形成的数据框
final_data = []

# 使用zip函数捆绑两列,并使用for循环
for Id,CellBehaviorData in zip(data2.Id, data2.CellBehaviorData):    
   # 组装数据框    mydf = pd.DataFrame(json.loads(CellBehaviorData[1:-1])['behavior'])
   # 将数据框与变量Id组装起来    final_data.append(pd.concat([pd.Series(np.repeat(Id,mydf.shape[0]), name = 'Id'),mydf], axis = 1))
#这个地方写点自己看作者文档遇到的一些困难, 主要是repeat函数的用法np.repeat(Id,mydf.shape[0])表示的就是取Id的值然后复制mydf.shape[0]次
# 构造最终的数据框    
final_data = pd.concat(final_data)# 数据类型转换

# 挑选需要转换类型的变量名称
vars = ['call_cnt','call_in_cnt','call_in_time','call_out_cnt','call_out_time','net_flow','sms_cnt','total_amount']
# 对以上变量进行数据类型转换
df_convert = final_data[vars].apply(lambda x: x.astype('float'))

# 从新完成数据合并
final_data2 = pd.concat([df_convert, final_data.loc[:,~final_data.columns.isin(vars)]], axis = 1) final_data2

# 对每个id计算近三个月的平均指标值
stats = final_data2.loc[final_data2.cell_mth.isin(['2017-08','2017-07','2017-06']),:].groupby('Id').aggregate(np.mean) stats

      虽然通过上面的方法可以实现数据的关联和匹配,但个人觉得并不是很理想,因为这里毕竟使用了for循环,一旦数据量大的话,执行起来会比较缓慢,如果高人,还请指点。

结语

      OK,今天关于半结构化的json数据转数据框的分享就介绍到到这里,希望本篇文章对各位网友有一定的帮助。如果你有任何问题,欢迎在公众号的留言区域表达你的疑问。欢迎各位朋友继续转发与分享文中的内容,让更多的朋友学习和进步。有关文中的脚本和数据可至下方的链接获取,再次感谢网友对我的关注和支持。

关注“每天进步一点点2015

相关材料下载链接

链接: https://pan.baidu.com/s/1kVzNnFp 密码: tdkm

### YOLO目标检测模型实现程 #### 了解YOLO基本概念和架构 深入理解YOLO的目标检测方法对于成功实施至关重要。YOLO是一种实时对象检测算法,它将输入图像划分为网格,并预测每个网格单元内的边界框及其对应的类别概率[^1]。 #### 准备环境与安装依赖库 为了构建YOLO模型,需先设置开发环境并安装必要的Python包。通常情况下这包括但不限于`numpy`, `opencv-python`, 和 `tensorflow` 或者 `pytorch`框架之一。可以通过pip工具来完成这些软件包的安装: ```bash pip install numpy opencv-python tensorflow ``` #### 获取预训练权重文件 利用已有的预训练模型可以加速项目的进展并且提高准确性。可以从官方资源或者其他可靠的第三方平台下载适合版本(如YOLOv3, v4等)的权重文件[^2]。 #### 加载网络结构配置及初始化模型 加载Darknet风格的.cfg配置文件定义神经网络层参数;接着读取刚才获取到的.weights格式权值数据填充至相应位置形成完整的YOLO实例化对象。下面是一个简单的例子展示如何操作PyTorch版YOLO: ```python import torch from models import * # 假设这是包含了YOLO类定义的一个模块 device = 'cuda' if torch.cuda.is_available() else 'cpu' model = Darknet('cfg/yolov3.cfg').to(device) if device == 'cuda': model.load_darknet_weights('weights/yolov3.weights') else: model.load_state_dict(torch.load('weights/yolov3.pt', map_location=device)['model']) ``` #### 数据处理与增强 准备用于训练的数据集非常重要。一般会涉及到图片标注信息整理成特定格式供后续解析使用,比如VOC或COCO标准。另外还可以考虑加入一些随机变换作为数据扩增手段提升泛化能力,像水平翻转、颜色抖动等等。 #### 训练过程概述 一旦准备好所有前期准备工作之后就可以着手于正式开始了!设定好超参后启动迭代循环,在每轮epoch结束时评估验证集上的表现情况调整策略直至收敛满意为止。期间要注意监控loss变化趋势以及mAP指标进步幅度确保方向正确无误。 #### 测试阶段 当训练完成后便进入到最终环节——测试。选取部分未见过的新样本送入已经训练好的YOLO当中去检验其识别效果是否达到预期目的。如果一切顺利的话就能看到清晰准确的结果啦!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值