在使用数据过程中,我们常常会遇到NULL值,对于NULL的存在,你们是否在乎呢?
常见的场景:使用Excel进行合并单元格的数据时,将他们录入数据库或者加载到PowerBI,合并单元格的数据只显示一行有数据,其它则显示NULL,这种情况需要对数据空值进行填充,才能真正用于可视化和报表开发;
如果未处理,则可视化可能会出现下面情况:
实际场景:有这样一份关于企业用户数的每天记录,但由于系统原因常常出现有些天企业用户数没有进行统计,测试数据如下:
create table wechat ( date1 date, num int); insert into wechat values ('2022-07-01', 5), ('2022-07-02', 6), ('2022-07-03', null), ('2022-07-04', 7), ('2022-07-05', null), ('2022-07-06', null), ('2022-07-07', 8), ('2022-07-08', null), ('2022-07-09', null), ('2022-07-10', null), ('2022-07-11', 9);
针对于这些没有统计的日期,进行补0不太正常,企业用户数也不太可能一下子减为0,所以客户希望可以根据最近一天的用户数进行填充。
需求分析:客户希望根据最近一天的用户数进行填充NULL值,那么这样的话就有两种情况,根据前一天向下填充用户数和后一天向上填充用户数,我们知道Power Query在功能栏上可以直接点击实现,那如何在SQL和Python中进行实现呢?
Mysql 实现向下或向上填充
count(字段):统计不为NULL的记录数;
在这里小编巧妙的运用了count(column) 和开窗函数结合,这样就计算出了累计不为NULL的记录数,然后根据记录数进行分组,取组内最大值进行填充,这样便解决了问题;
由于Mysql窗口函数不太支持添加 ignore nulls ,这里采用了子查询方式处理,如果有需要小编也可以准备一份Oracle的处理方式哦!
select date1, num, max(num) over (partition by a) num_next, -- 向下填充 max(num) over (partition by b) num_up -- 向上填充 from (select date1, num, count(num) over w1 a, -- 向下累计不为null的记录数 count(num) over w2 b -- 向上累计不为null的记录数 from wechat window w1 as (order by date1), w2 as (order by date1 desc)) t order by date1;
data1 | num | num_next | num_up |
2022-07-01 | 5 | 5 | 5 |
2022-07-02 | 6 | 6 | 6 |
2022-07-03 | 6 | 7 | |
2022-07-04 | 7 | 7 | 7 |
2022-07-05 | 7 | 8 | |
2022-07-06 | 7 | 8 |
2022-07-07 | 8 | 8 | 8 |
2022-07-08 | 8 | 9 | |
2022-07-09 | 8 | 9 | |
2022-07-10 | 8 | 9 | |
2022-07-11 | 9 | 9 | 9 |
Python 实现向下或向上填充
对于空值的处理Python有专门的fillna函数处理,有兴趣的同学可以去官网进行查阅:fillna语法
在这里我们进行了简单的使用:
- method=‘ffill’ 使用前一个不为空的值填充
- method=‘bfill’ 使用后一个不为空的值填充
# 导入所需要的模块 import pandas as pd from sqlalchemy import create_engine # 与本地数据库建立连接 engine = create_engine(str(r'mysql+pymysql://%s:' '%s' '@%s/%s' '?charset=UTF8MB4')%('root', '1q2w3e4r', '127.0.0.1', 'test')) # 获取测试数据 sql1 = " select * from wechat " data1 = pd.read_sql_query(sql1,engine) ### 以上是测试数据在Mysql数据库中的获取方法,也可直接读取CSV文件如下 ### # 直接读取CSV文件测试数据 data1 = pd.read_csv('/Users/guanfawang/Desktop/test.csv') # 向下填充 data1.insert(loc=2,column='num_next',value=data1['num'].fillna(method='ffill')) # 向上填充 data1.insert(loc=3,column='num_up',value=data1['num'].fillna(method='bfill')) data1
data1 | num | num_next | num_up |
2022-07-01 | 5 | 5 | 5 |
2022-07-02 | 6 | 6 | 6 |
2022-07-03 | 6 | 7 | |
2022-07-04 | 7 | 7 | 7 |
2022-07-05 | 7 | 8 | |
2022-07-06 | 7 | 8 |
2022-07-07 | 8 | 8 | 8 |
2022-07-08 | 8 | 9 | |
2022-07-09 | 8 | 9 | |
2022-07-10 | 8 | 9 | |
2022-07-11 | 9 | 9 | 9 |
总结
在实际应用中,出现NULL值我们一定要特别注意,避免后面开发报表出现新的问题,所以建议尽早发现NULL,并且及时沟通商量应对方案,以上是针对不同工具实现的填充,还有更高阶的填充呢方案,我将会在后期给大家分享,记得关注哦!