- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
数据清洗是指在数据处理过程中对原始数据进行筛选、转换和修正,以确保数据的准确性、一致性和完整性的过程。它是数据预处理的一部分,旨在处理和纠正可能存在的错误、缺失值、异常值和不一致性等数据质量问题.
为什么要数据清洗 。
Excel在数据采集场景中非常常用。作为一款电子表格软件,它提供了丰富的功能和易用的界面,使其成为大部分人首选的数据采集工具之一.
而在数据采集的过程中,因为采集渠道多样,数据格式也多种多样,从而会出现部分数据的丢失和不准确的情况,因此为了处理掉这些 “垃圾”数据,需要对数据进行清洗.
哪些数据需要进行清洗 。
通常在这几种情况下需要进行数据清洗.
1.缺失数据处理:数据在采集或迁移的过程中,出现数据的遗漏.
2.错误数据判断:数据在采集或迁移的过程中与原数据不一致.
3.重复数据处理:一条数据重复出现多次.
4.数据格式转换:数据在采集或迁移的过程中出现了乱码.
下面让我们看一下数据清洗都会涉及的处理步骤:
GcExcel提供了 IRange(区域) 的概念,可以通过API快速的读取有数据的区域。POI和EasyExcel(POJO注解)则需要遍历每一个单元格.
根据业务需求,可以选择使用API,也可以选择遍历所有单元格.
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上的第几列,因此获取默认值时使用该方法.
错误数据的判断,与缺失数据处理相似,通过制定一些规则找出错误的值,对于错误值可以通过修改背景颜色进行高亮处理,用来提示,进行人工修改.
通常规则可以有两种选择:
假如我们有下面一份数据,其中联系电话中有两条是错误的,位数不够,货物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批量数据清洗变得简单高效!的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
就目前而言,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引起辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visit the he
我正在尝试理解 promise ,在本例中是在一个循环中。 我的场景基于将文件上传到 Google 云端硬盘。我的理解是,每个文件都应该上传,然后一旦 promise 得到解决,就上传下一个文件,依此
JDK 1.6 包括通过 JAX-WS API 使用 FastInfoset Web 服务的功能。这些的实现隐藏在 com.sun.xml.internal 的深处,包名旨在让任何明智的 Java 开
我正在学习 React 并思考组件的结构。以下内容让我有些困惑。 我们被告知应该有单一的真相来源。 所有者组件应将 props/状态传递给它的责任(有些人称为“ownee”)组件。 所以,如果我自己的
我刚刚开始使用 Google Guice 作为依赖项注入(inject)框架,并试图将其改造为我最近编写的中小型项目。我了解 Guice 工作原理的基础知识,但对一些方法细节有点模糊。例如: 1) 模
上周我们在上周左右的修补和测试后将 Omniture 的分析代码发布到大量网站上。 在我们几乎所有的网站模板上,它都运行良好。在一些零星的、不可预测的情况下,严重的浏览器崩溃体验可能会让一些用户望而却
我刚刚获得了一个 API,它似乎比我习惯的更上一层楼,因为一切似乎都是使用接口(interface)实现的,我正在努力理解它们。 public partial class Form1 : Form,
我的程序似乎很合我意。但是,当我编译它时,我收到了这条消息: Note: Program.java uses unchecked or unsafe operations. Note: Recompi
最近开始用story board、Xcode等学习Swift。我很难理解 ViewController 代码的原理,因为它似乎遗漏了很多基本要素——大概是为了尝试让事情变得更简单——但它不适合来自其他
我刚收到一些有关使用 wpf、c# 的 MVVM 的设计/实现问题。我只是想掌握 MVVM,如果有人能证实我的想法,我正在徘徊,在我的应用程序中,我需要一名员工、一个部门和一家公司。所以换句话说,我有
我在 gird View 中有一个 gridview 和 2 个链接按钮,编辑和删除,单击编辑按钮 s 时,该行的详细信息应显示在“detailsview”中。我的详细信息 View 在更新面板。 最
function def() { console.log(this.x) } var f = def.bind({ x:777 }) f() // prints 777 bind 创建了一个函
我尝试将谷歌地图(外部加载的脚本)添加到 meteor 应用程序,但没有成功,我注意到有两种问题: 如果我做简单的事情并将主要的 API 脚本添加到我的 ,然后它被呈现为last。 发生这种情况时,
如果我理解正确,Node JS 是非阻塞的......所以它不是等待来自数据库或其他进程的响应,而是转移到其他东西并稍后再检查。 它也是单线程的。 这是否意味着给定的 Node JS 进程可以充分有效
几周前,我开始了 Iphone 应用程序开发的研究,在不同设置中进行了大量的 hello world 应用程序之后,我现在已经准备好开发我的第一个基于 Cocoa 中使用的 MVC 设计模式的应用程序
这个问题和我之前的问题很相似。 大约 4 年前,我在 Visual Studio 2005 中使用过 ASP .Net。恢复最新版本需要多长时间? 最佳答案 这取决于您“使用”它的程度。有经验的开发人
如何让这个程序让用户一次输入 5 位数字,而不是每次都询问单独的数字?我知道我必须使用 string.split() 但我将在哪里放置代码并执行代码。 Heading from random impo
因此,根据我的理解,在 3nf 数据库中,主键值可用于确定表中的每个其他属性。 这是否意味着外键将专门用于创建复合实体?外键如何适合 3nf 数据库? 有哪些“迹象”表明我的数据库已标准化?数据库中的
如何解决以下 f(n)=n!据我所知不适用于主定理的任何情况。T(n) = 16T(n/4) + n! 最佳答案 David Eisenstat 部分正确。情况 3 确实适用,但 T(n) = the
在过去的 2.5 年里,我一直在研究 SAP 技术。由于技术概念太多,我无法找到一个可以了解与它相关的所有内容的单一来源。我没有掌握掌握所有技术概念的信心。 如果您遇到过这样的经历以及如何克服它,请帮
我是一名优秀的程序员,十分优秀!