掌握这些技巧,让Excel批量数据清洗变得简单高效!

掌握,这些,技巧,excel,批量,数据,清洗,变得,简单,高效 · 浏览次数 : 3

小编点评

**场景一:重复数据处理** ```java public void removeDuplicateData() { Workbook workbook = new Workbook(); workbook.open("resources/DuplicateRows.xlsx"); IWorksheet sheet = workbook.getActiveSheet(); IRange usedRange = sheet.getUsedRange(); HashSet set = new HashSet<>(); Stack deleteRows = new Stack<>(); for (int r = 1; r < usedRange.getRows().getCount(); r++) { IRange row = usedRange.getRows().get(r); StringBuilder rowKey = new StringBuilder(); for (int c = 0; c < row.getColumns().getCount(); c++) { rowKey.append(usedRange.get(r, c).getValue().toString()); } if (set.contains(rowKey.toString())) { deleteRows.push(row); } else { set.add(rowKey.toString()); } } while (!deleteRows.isEmpty()) { deleteRows.pop().delete(); } workbook.save("Result.xlsx"); } ``` **场景二:数据格式转换** ```java public void unifyFormat() { Workbook workbook = new Workbook(); workbook.open("resources/DifferentFormat.xlsx"); IWorksheet sheet = workbook.getActiveSheet(); IRange usedRange = sheet.getUsedRange(); for (int row = 1; row < usedRange.getRows().getCount(); row++) { IRange dateCell = usedRange.get(row, 1); IRange priceCell = usedRange.get(row, 2); dateCell.setValue(parseDate(dateCell.getValue())); priceCell.setValue(parsePrice(priceCell.getValue())); priceCell.setNumberFormat("¥0.00"); } sheet.getRange("B1").setNumberFormat("\"); workbook.save("Result.xlsx"); } ``` **场景三:Excel服务端导入导出项目实战** ```java @RestController @RequestMapping("/excel") public class ExcelController { @ExcelImport public void importExcel(@ExcelImportWorkbook workbook) { // 处理 Excel 报表数据 } } ``` **扩展链接:** * Spring Boot框架下实现Excel服务端导入导出项目实战: *在线报价采购系统(React +SpreadJS+Echarts)React + Springboot + Quartz * 从0实现Excel报表自动化

正文

什么是数据清洗

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

为什么要数据清洗

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,如下(在文件中查找特殊单元格):

Workbook workbook = new Workbook();
 workbook.open("data.xlsx");
 IWorksheet sheet = workbook.getActiveSheet();

 //寻找sheet中,使用到的所有单元格
 IRange usedRange = sheet.getUsedRange();

 //寻找所有的公式单元格
 IRange allFormulas = sheet.getCells().specialCells(SpecialCellType.Formulas);
 //寻找所有的常量单元格
 IRange allConstants = sheet.getCells().specialCells(SpecialCellType.Constants);

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

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

场景一:缺失数据处理

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

代码如下:

public void replaceBlankCell() {
   Workbook workbook = new Workbook();
   workbook.open("resources/BlankCells.xlsx");
   IWorksheet sheet = workbook.getActiveSheet();
   IRange blankRanges = sheet.getCells().specialCells(SpecialCellType.Blanks);
   for (IRange area : blankRanges.getAreas()) {
     for (int column = 0; column < area.getColumns().getCount(); column++) {
       for (int row = 0; row < area.getRows().getCount(); row++) {
         IRange cell = area.get(row, column);
         Object defaultVal = getDefaultVal(cell.getColumn());
         cell.setValue(defaultVal);
       }
     }
   }

   workbook.save("Result.xlsx");
 }

 private Object getDefaultVal(int column) {
   switch (column) {
     case 1:
       return "匿名";
     case 2:
       return -1;
     case 3:
       return "N/A";
     case 4:
       return "未知";
   }
   return null;
 }

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

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

场景二:错误数据判断

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

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

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

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

public void MarkErrorData(){
   Workbook workbook = new Workbook();
   workbook.open("resources/ErrorData.xlsx");
   IWorksheet sheet = workbook.getActiveSheet();

   IRange telRange = sheet.getRange("C2:D5");
   for (int r=0; r<telRange.getRows().getCount();r++){
     IRange cell = telRange.get(r,0);
     if(cell.getValue().toString().length() != 11){
       cell.getInterior().setColor(Color.GetOrangeRed());
     }
   }

   IFormatCondition condition =
       (IFormatCondition) sheet.getRange("D2:D5").getFormatConditions().
           add(FormatConditionType.CellValue, FormatConditionOperator.Less, 1, null);
   condition.getInterior().setColor(Color.GetOrangeRed());

   workbook.save("Result.xlsx");
 }


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

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

场景三:重复数据处理

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

public void RemoveDuplicateData() {
   Workbook workbook = new Workbook();
   workbook.open("resources/DuplicateRows.xlsx");
   IWorksheet sheet = workbook.getActiveSheet();
   IRange usedRange = sheet.getUsedRange();
   HashSet<String> set = new HashSet<>();
   Stack<IRange> deleteRows = new Stack<>();
   for (int r = 1; r < usedRange.getRows().getCount(); r++) {
     IRange row = usedRange.getRows().get(r);
     StringBuilder rowKey = new StringBuilder();
     for (int c = 0; c < row.getColumns().getCount(); c++) {
       rowKey.append(usedRange.get(r, c).getValue().toString());
     }
     if (set.contains(rowKey.toString())) {
       deleteRows.push(row);
     } else {
       set.add(rowKey.toString());
     }
   }

   while (!deleteRows.isEmpty()) {
     deleteRows.pop().delete();
   }

   workbook.save("Result.xlsx");
 }


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

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

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

场景四:数据格式转换

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

代码如下:

public void unifyFormat() {
   Workbook workbook = new Workbook();
   workbook.open("resources/DifferentFormat.xlsx");
   IWorksheet sheet = workbook.getActiveSheet();
   IRange usedRange = sheet.getUsedRange();
   for (int row = 1; row < usedRange.getRows().getCount(); row++) {
     IRange dateCell = usedRange.get(row, 1);
     IRange priceCell = usedRange.get(row, 2);
     dateCell.setValue(parseDate(dateCell.getValue()));
     dateCell.setNumberFormat("yyyy年MM月dd日");
     priceCell.setValue(parsePrice(priceCell.getValue()));
     priceCell.setNumberFormat("¥0.00");
   }
   sheet.getRange("B1").setNumberFormat("");

   workbook.save("Result.xlsx");
 }

 private Double parsePrice(Object value) {
   if (value == null)
     return null;
   String val = value.toString();
   if (val.startsWith("$") || val.startsWith("¥")) {
     val = val.substring(1);
   }
   return Double.parseDouble(val);
 }

 private LocalDateTime parseDate(Object value) {
   if (value == null)
     return null;
   if (value instanceof LocalDateTime) {
     return (LocalDateTime) value;
   }
   DateTimeFormatter[] formatters = {
       DateTimeFormatter.ofPattern("yyyy/MM/dd"),
       DateTimeFormatter.ofPattern("MM-dd-yyyy"),
       DateTimeFormatter.ofPattern("yyyy年MM月dd日"),
       DateTimeFormatter.ofPattern("yyyy.MM.dd")
   };
   LocalDate datetime = null;

   for (DateTimeFormatter formatter : formatters) {
     try {
       datetime = LocalDate.parse(value.toString(), formatter);
       break;
     } catch (DateTimeParseException e) {
       e.printStackTrace();
     }
   }

   assert datetime != null;
   return datetime.atStartOfDay();
 }

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


扩展链接:

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

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

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

与掌握这些技巧,让Excel批量数据清洗变得简单高效!相似的内容:

掌握这些技巧,让Excel批量数据清洗变得简单高效!

什么是数据清洗 数据清洗是指在数据处理过程中对原始数据进行筛选、转换和修正,以确保数据的准确性、一致性和完整性的过程。它是数据预处理的一部分,旨在处理和纠正可能存在的错误、缺失值、异常值和不一致性等数据质量问题。 为什么要数据清洗 Excel在数据采集场景中非常常用。作为一款电子表格软件,它提供了丰

Spring Cloud Gateway编码实现任意地址跳转

面对同样的客户端请求,SpringCloud Gateway可以转发给不同的服务去处理,掌握这个技能,让请求从微服务入口处被掌控,被调度

<Python全景系列-1> Hello World,1分钟配置好你的python环境

欢迎来到我们的系列博客《Python360全景》!在这个系列中,我们将带领你从Python的基础知识开始,一步步深入到高级话题,帮助你掌握这门强大而灵活的编程语法。无论你是编程新手,还是有一定基础的开发者,这个系列都将提供你需要的知识和技能。这是我们的第一篇文章,让我们从最基础的开始:如何在你的电脑上配置Python环境。

图解算法,原理逐步揭开「GitHub 热点速览」

想必每个面过大厂的小伙伴都被考过算法,那么有没有更快了解算法的方式呢?这是一个老项目,hello-algo 用图解的方式让你了解运行原理。此外,SQL 闯关自学项目也是一个让你能好好掌握 SQL 技术的仓库。说回到面试,这个一周获得近 10k star 的 devops-exercises 定能让你好好刷一场面经。

C#/.NET这些实用的编程技巧你都会了吗?

DotNet Exercises介绍 DotNetGuide专栏C#/.NET/.NET Core编程常用语法、算法、技巧、中间件、类库练习集,配套详细的文章教程讲解,助你快速掌握C#/.NET/.NET Core各种编程常用语法、算法、技巧、中间件、类库等等。 GitHub开源地址:https:/

4.10 x64dbg 反汇编功能的封装

LyScript 插件提供的反汇编系列函数虽然能够实现基本的反汇编功能,但在实际使用中,可能会遇到一些更为复杂的需求,此时就需要根据自身需要进行二次开发,以实现更加高级的功能。本章将继续深入探索反汇编功能,并将介绍如何实现反汇编代码的检索、获取上下一条代码等功能。这些功能对于分析和调试代码都非常有用,因此是书中重要的内容之一。在本章的学习过程中,读者不仅可以掌握反汇编的基础知识和技巧,还能够了解如

[译]这几个CSS小技巧,你知道吗?

# 前言 在网页设计和前端开发中,CSS属性是非常重要的一部分。掌握常用的CSS属性不仅可以使你的网页看起来更美观,还能提升用户体验,今天小编为大家介绍8个常见的CSS小技巧: # 1.修改滚动条样式 下图是我们常见的滚动条,现在需要改变滚动条的宽度和颜色了,并把它画的圆一点。 ![](https:

GO数组解密:从基础到高阶全解

在本文中,我们深入探讨了Go语言中数组的各个方面。从基础概念、常规操作,到高级技巧和特殊操作,我们通过清晰的解释和具体的Go代码示例为读者提供了全面的指南。无论您是初学者还是经验丰富的开发者,这篇文章都将助您更深入地理解和掌握Go数组的实际应用。 关注公众号【TechLeadCloud】,分享互联网

[转帖]【基础】HTTP、TCP/IP 协议的原理及应用

https://juejin.cn/post/6844903938232156167 前言 本文将持续记录笔者在学习过程中掌握的一些 HTTP 、TCP/IP 的原理,以及这些网络通信技术的一些应用场景,文章会保持更新,相当于对这块知识的一个总结和归纳。有不正确之处欢迎指出,及时改正~ 纲要 访问网

< Python全景系列-6 > 掌握Python面向对象编程的关键:深度探索类与对象

Python全景系列的第六篇,本文将深入探讨Python语言中的核心概念:类(Class)和对象(Object)。我们将介绍这些基本概念,然后通过示例代码详细展示Python中的类和对象如何工作,包括定义、实例化和修改等操作。本文将帮助您更深入地理解Python中的面向对象编程(OOP),并从中提出一些不常见但很有用的技术观点。