什么是数据清洗

数据清洗是指在数据处理过程中对原始数据进行筛选、转换和修正,以确保数据的准确性、一致性和完整性的过程。它是数据预处理的一部分,旨在处理和纠正可能存在的错误、缺失值、异常值和不一致性等数据质量问题。

为什么要数据清洗

Excel在数据采集场景中非常常用。作为一款电子表格软件,它提供了丰富的功能和易用的界面,使其成为大部分人首选的数据采集工具之一。

而在数据采集的过程中,因为采集渠道多样,数据格式也多种多样,从而会出现部分数据的丢失和不准确的情况,因此为了处理掉这些 “垃圾”数据,需要对数据进行清洗。

哪些数据需要进行清洗

通常在这几种情况下需要进行数据清洗。

1.缺失数据处理:数据在采集或迁移的过程中,出现数据的遗漏。

2.错误数据判断:数据在采集或迁移的过程中与原数据不一致。

3.重复数据处理:一条数据重复出现多次。

4.数据格式转换:数据在采集或迁移的过程中出现了乱码。

数据清洗都需要做些什么

下面让我们看一下数据清洗都会涉及的处理步骤:

  1. 分析需求:通过对数据原本的格式,特征进行分析,规划数据清洗的业务规则及需求。
  2. 打开文件:把Excel文件打开,通常这一步需要依赖Excel组件库,比如使用POI,GcExcel,EasyExcel等。
  3. 读取数据:通过Excel库中的API,读取需要操作的数据,这里比较一下三个产品的特点:

GcExcel提供了IRange(区域)的概念,可以通过API快速的读取有数据的区域。POI和EasyExcel(POJO注解)则需要遍历每一个单元格。

根据业务需求,可以选择使用API,也可以选择遍历所有单元格。

  1. 数据清洗:根据需求,结合Excel库的API,进行数据清洗。如:用默认值填写缺失数据的单元格,删除整个空行,删除重复数据,把不符合范围的数据删除掉,或者把日期数字的格式统一起来,等等。
  2. 数据持续化:把处理好的数据回存至Excel文件,或者保存在数据库中或者CSV文件中。

如何使用GcExcel实现数据清洗

GcExcel有IRange的API,可以让数据清洗时代码写的更简单,因此下面我们选择用GcExcel的代码为例解决上面提到的几个场景。

基于IRange,GcExcel提供一些快速查找的API,如下(在文件中查找特殊单元格):

  1. Workbook workbook = new Workbook();
  2. workbook.open("data.xlsx");
  3. IWorksheet sheet = workbook.getActiveSheet();
  4. //寻找sheet中,使用到的所有单元格
  5. IRange usedRange = sheet.getUsedRange();
  6. //寻找所有的公式单元格
  7. IRange allFormulas = sheet.getCells().specialCells(SpecialCellType.Formulas);
  8. //寻找所有的常量单元格
  9. IRange allConstants = sheet.getCells().specialCells(SpecialCellType.Constants);

虽然GcExcel提供了API,但数据清洗时,也可能有需求需要遍历,下面是GcExcel遍历单元格的代码,后面我们就有可能会用到。

  1. public void FetchCellBasedOnRange(IRange area) {
  2. for (int column = 0; column < area.getColumns().getCount(); column++) {
  3. for (int row = 0; row < area.getRows().getCount(); row++) {
  4. IRange cell = area.get(row, column);
  5. //获取单元格的值
  6. Object val = cell.getValue();
  7. }
  8. }
  9. }

场景一:缺失数据处理

假如有一个Excel的数据,现在蓝色的格子是空的,我们需要对不同列下的蓝色格子做不同的处理,例如姓名的空格子替换为匿名,年龄替换成-1,身份证号填写N/A,住址填写为未知。

代码如下:

  1. public void replaceBlankCell() {
  2. Workbook workbook = new Workbook();
  3. workbook.open("resources/BlankCells.xlsx");
  4. IWorksheet sheet = workbook.getActiveSheet();
  5. IRange blankRanges = sheet.getCells().specialCells(SpecialCellType.Blanks);
  6. for (IRange area : blankRanges.getAreas()) {
  7. for (int column = 0; column < area.getColumns().getCount(); column++) {
  8. for (int row = 0; row < area.getRows().getCount(); row++) {
  9. IRange cell = area.get(row, column);
  10. Object defaultVal = getDefaultVal(cell.getColumn());
  11. cell.setValue(defaultVal);
  12. }
  13. }
  14. }
  15. workbook.save("Result.xlsx");
  16. }
  17. private Object getDefaultVal(int column) {
  18. switch (column) {
  19. case 1:
  20. return "匿名";
  21. case 2:
  22. return -1;
  23. case 3:
  24. return "N/A";
  25. case 4:
  26. return "未知";
  27. }
  28. return null;
  29. }

要注意的是,sheet.getCells().specialCells(SpecialCellType.Blanks);返回的区域是多个,因此我们需要遍历通过遍历areas来对每一个区域进行遍历。

cell.getColumn()可以获取到当前格子对应到sheet上的第几列,因此获取默认值时使用该方法。

场景二:错误数据判断

错误数据的判断,与缺失数据处理相似,通过制定一些规则找出错误的值,对于错误值可以通过修改背景颜色进行高亮处理,用来提示,进行人工修改。

通常规则可以有两种选择:

  1. 使用Java直接编写判断逻辑。
  2. 使用数据校验(Datavalidation)功能,或者条件格式(ConditionFormat)来进行处理。

假如我们有下面一份数据,其中联系电话中有两条是错误的,位数不够,货物ID有两条是错误的,货物ID不能小于0,我们需要把他们找出来。

  1. public void MarkErrorData(){
  2. Workbook workbook = new Workbook();
  3. workbook.open("resources/ErrorData.xlsx");
  4. IWorksheet sheet = workbook.getActiveSheet();
  5. IRange telRange = sheet.getRange("C2:D5");
  6. for (int r=0; r<telRange.getRows().getCount();r++){
  7. IRange cell = telRange.get(r,0);
  8. if(cell.getValue().toString().length() != 11){
  9. cell.getInterior().setColor(Color.GetOrangeRed());
  10. }
  11. }
  12. IFormatCondition condition =
  13. (IFormatCondition) sheet.getRange("D2:D5").getFormatConditions().
  14. add(FormatConditionType.CellValue, FormatConditionOperator.Less, 1, null);
  15. condition.getInterior().setColor(Color.GetOrangeRed());
  16. workbook.save("Result.xlsx");
  17. }

在代码中,我们对C2:C5进行遍历,判断字符串长度,然后对长度不合法的数据进行颜色标记。

而对于货物,设置了条件格式,可以让Excel在打开时,自行标记错误的数据。

场景三:重复数据处理

假如我们有一份数据,其中有一些行数据是完全重复的,我们需要删除这些行,如图所示。

  1. public void RemoveDuplicateData() {
  2. Workbook workbook = new Workbook();
  3. workbook.open("resources/DuplicateRows.xlsx");
  4. IWorksheet sheet = workbook.getActiveSheet();
  5. IRange usedRange = sheet.getUsedRange();
  6. HashSet<String> set = new HashSet<>();
  7. Stack<IRange> deleteRows = new Stack<>();
  8. for (int r = 1; r < usedRange.getRows().getCount(); r++) {
  9. IRange row = usedRange.getRows().get(r);
  10. StringBuilder rowKey = new StringBuilder();
  11. for (int c = 0; c < row.getColumns().getCount(); c++) {
  12. rowKey.append(usedRange.get(r, c).getValue().toString());
  13. }
  14. if (set.contains(rowKey.toString())) {
  15. deleteRows.push(row);
  16. } else {
  17. set.add(rowKey.toString());
  18. }
  19. }
  20. while (!deleteRows.isEmpty()) {
  21. deleteRows.pop().delete();
  22. }
  23. workbook.save("Result.xlsx");
  24. }

可以看到,重复的行被移除掉了。代码中用到了哈希set和栈,其中我们用哈希set来查找重复的行。

另外使用栈来记录需要被删除的行,这里特地用了栈,而没有使用队列,数组或者ArraryList的原因是,GcExcel在删除一行时,会让这行下面的数据上移,这样我们之前记录的行就会便宜,导致删除错误的行。

简而言之,我们需要从下向上删除,来避免行位移导致删错的问题。

场景四:数据格式转换

例如我们有一些日期数据,或者货币数据,在数据采集时数据格式不同,我们需要分别统一订单日期,金额的格式。

代码如下:

  1. public void unifyFormat() {
  2. Workbook workbook = new Workbook();
  3. workbook.open("resources/DifferentFormat.xlsx");
  4. IWorksheet sheet = workbook.getActiveSheet();
  5. IRange usedRange = sheet.getUsedRange();
  6. for (int row = 1; row < usedRange.getRows().getCount(); row++) {
  7. IRange dateCell = usedRange.get(row, 1);
  8. IRange priceCell = usedRange.get(row, 2);
  9. dateCell.setValue(parseDate(dateCell.getValue()));
  10. dateCell.setNumberFormat("yyyy年MM月dd日");
  11. priceCell.setValue(parsePrice(priceCell.getValue()));
  12. priceCell.setNumberFormat("¥0.00");
  13. }
  14. sheet.getRange("B1").setNumberFormat("");
  15. workbook.save("Result.xlsx");
  16. }
  17. private Double parsePrice(Object value) {
  18. if (value == null)
  19. return null;
  20. String val = value.toString();
  21. if (val.startsWith("$") || val.startsWith("¥")) {
  22. val = val.substring(1);
  23. }
  24. return Double.parseDouble(val);
  25. }
  26. private LocalDateTime parseDate(Object value) {
  27. if (value == null)
  28. return null;
  29. if (value instanceof LocalDateTime) {
  30. return (LocalDateTime) value;
  31. }
  32. DateTimeFormatter[] formatters = {
  33. DateTimeFormatter.ofPattern("yyyy/MM/dd"),
  34. DateTimeFormatter.ofPattern("MM-dd-yyyy"),
  35. DateTimeFormatter.ofPattern("yyyy年MM月dd日"),
  36. DateTimeFormatter.ofPattern("yyyy.MM.dd")
  37. };
  38. LocalDate datetime = null;
  39. for (DateTimeFormatter formatter : formatters) {
  40. try {
  41. datetime = LocalDate.parse(value.toString(), formatter);
  42. break;
  43. } catch (DateTimeParseException e) {
  44. e.printStackTrace();
  45. }
  46. }
  47. assert datetime != null;
  48. return datetime.atStartOfDay();
  49. }

需要注意的是在处理日期和金额时,由于value的类型不太一致,需要写特定的方法来进行处理。

扩展链接:

Spring Boot框架下实现Excel服务端导入导出

项目实战:在线报价采购系统(React +SpreadJS+Echarts)

React + Springboot + Quartz,从0实现Excel报表自动化

掌握这些技巧,让Excel批量数据清洗变得简单高效!的更多相关文章

  1. 订餐系统之Excel批量导入

    批量导入现在基本已经成为各类系统的标配了,当前,我们订餐系统也不例外,什么商家呀.商品呀.优惠码之类的,都少不了.毕竟嘛,对非开发人员来说,看到Excel肯定比看到很多管理系统还是要亲切很多的.这里, ...

  2. 利用Excel批量高速发送电子邮件

    利用Excel批量高速发送电子邮件,分两步: 1. 准备待发送的数据: a.) 打开Excel,新建Book1.xlsx b.) 填入以下的内容, 第一列:接收人,第二列:邮件标题,第三列:正文,第四 ...

  3. Unix时间戳转换怎样在Excel批量修改?

    最近在操作项目的时候碰到一个Unix时间戳转换的问题."date_time":1393031347这个是什么,你知道吗?如果你对Unix时间戳了解的话一眼就看出来.但我们本着科普的 ...

  4. excel 批量替换换行符

    在excel批量替换换行符操作步骤: 全选需要查找换行符的范围 CTRL+H调出查找和替换 在查找内容内输入"ctrl+enter"两个组合键 点击查找全部即可. 在excel中输 ...

  5. Excel 批量快速合并相同的单元格:数据透视表、宏代码、分类汇总

    Excel 批量快速合并相同的单元格   在制作Excel表格的时候,为了使得自己制作的报表更加简洁明了,方便查阅,经常需要合并很多相同的单元格,如果有几千几万条记录需要合并的话,真的会让人发疯.怎样 ...

  6. Excel批量导入商品,遇到导入失败记录到另一个Excel中供下载查看

    /// <summary> /// EXCEL批量导入 /// </summary> /// <param name="filePath">文件 ...

  7. excel批量提取网页标题

    最近时间比较忙,有时候很多网页需要临时保存,以便空闲的时候查看.单纯的保存网页链接会让人很枯燥,所以需要自动批量提取标题. 为了这个小功能去写个小程序有点不划算,所以就利用excel实现了这个功能. ...

  8. zabbix3.4用Python脚本Excel批量导入主机

    1.安装xlrd读取Excel文件 1.1. 下载setuptools-38.2.4.zip,上传至zabbix服务器解压安装,下载地址:https://pypi.python.org/package ...

  9. 转载-用excel批量生成insert语句

    用excel批量生成insert语句   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/h ...

  10. # Excel批量处理数据

    Excel批量处理数据 拖住框下拉即可得到每行+3的结果

随机推荐

  1. MySQL中都有哪些锁?

    MySQL中都有哪些锁 为什么需要锁 在计算机系统中,锁(Lock)是一种同步机制,用于控制对共享资源的访问.它确保在任何给定时间内只有一个线程能够访问受保护的共享资源,从而避免了由并发访问导致的数据 ...

  2. 基于uniapp+vite4+vue3搭建跨端项目|uni-app+uview-plus模板

    最近得空学习了下uniapp结合vue3搭建跨端项目.之前也有使用uniapp开发过几款聊天/仿抖音/后台管理等项目,但都是基于vue2开发.随着vite.js破局出圈,越来越多的项目偏向于vue3开 ...

  3. CF1770F Koxia and Sequence

    一步都没想到,一定是状态不好吧,一定吧一定吧? 加训数数! 题意 给定 \(n, x, y\),定义好的序列 \(\{a_i\}_{i = 1}^n\) 满足 \(\sum\limits_{i = 1 ...

  4. 谁在以太坊区块链上循环交易?TuGraph+Kafka的0元流图解决方案

    都在说数据已经成为新时代的生产资料. 但随着大数据和人工智能等技术的发展,即便人们都知道数据的价值日益凸显,却无法凭借一己之力获取和分析如此大规模的数据. 要想富,先修路.要想利用新时代的数据致富,也 ...

  5. gitlab配置环境及pycharm配置

    一.gitlab介绍 GitLab 是一个用于仓库管理系统的开源项目,使用Git作为代码管理工具,并在此基础上搭建起来的web服务 git.gitlab.GitHub的简单区别 git 是一种基于命令 ...

  6. LSP协议被劫持,导致无法上网

    QQ无法登录,网页打不开 用火绒的断网修复 说已经修复了 结果屁用没有 然后找的百度经验 管理员打开命令行窗口 输入 netsh winsock reset catalog 重启即生效

  7. 根据模板动态生成word(二)使用poi生成word

    @ 目录 一.准备模板 1.创建模板文件 二.代码实践 1.引入依赖 2.自定义XWPFDocument 2.公用的方法和变量 3.工具类引用的包名 4.段落文本替换 5.图片替换 6.表格替换 7. ...

  8. java后台导出表格文件

    Java类所需jar包 import java.io.File; import java.io.IOException; import java.io.InputStream; import java ...

  9. 10/29/2017_C语言_三道题

    1. 用标准C编程:找出整形数字1-100之间的素数,并打印出来.(素数:除了1和自己本身可以被整除.) 2. 用标准C编程:有两个整形变量m.n,求出这两个数的最小公倍数. 3. 用标准C编程:输出 ...

  10. Linux: rsyslog.conf 配置

    refer to: https://www.debian.org/doc/manuals/debian-handbook/sect.syslog.en.html 日志子系统 Each log mess ...