Tablesaw
一. 前言
Tablesaw是一款Java的数据可视化库,主要包括两部分:
- 数据解析库,主要用于加载数据,对数据进行操作(转化,过滤,汇总等),类比Python中的Pandas库;
- 数据可视化库,将目标数据转化为可视化的图表,类比Python中的Matplotlib库。
与Pandas不同的是,Tablesaw中的表格以列(Column)为基本单位,因此大部分操作都是基于列进行的。当然也包括部分对行操作的函数,但是功能比较有限。
首先我们看一下Tablesaw支持的导入和导出文件的类型:
官方教程几乎包括了所有的操作:https://jtablesaw.github.io/tablesaw/userguide/toc,下面我就介绍一下我在写项目中使用到的一些操作。
二. Maven导入包
<dependency>
<groupId>tech.tablesaw</groupId>
<artifactId>tablesaw-core</artifactId>
<version>LATEST</version>
</dependency>
<dependency>
<groupId>tech.tablesaw</groupId>
<artifactId>tablesaw-excel</artifactId>
<version>LATEST</version>
</dependency>
三. 基本操作
3.1 列操作
Tablesaw中的列包括很多种数据类型,常用的包括:字符串列(StringColumn)、整型列(IntColumn)、浮点列(DoubleColumn)、日期时间列(DateTimeColumn)等,每一种列提供的API都大同小异。
3.1.1 创建列
/*1. 创建一个空列*/
DoubleColumn column = DoubleColumn.create("column name");
/*2. 创建一个有初始值的列*/
double[] values = {
1, 2, 3, 7, 9.44242, 11};
DoubleColumn column = DoubleColumn.create("column name", values);
3.1.2 添加、编辑和删除数据
/*添加数据*/
column.append(value)
/*编辑数据*/
doubleColumn.set(index, value);
/*删除数据*/
//方式1
column.setMissing(0);
column = column.removeMissing();
//方式2
//这里用到了后面过滤的api
column.setMissing(index);
Selection sl = column.isNotMissing();
column = column.where(sl);
3.1.3 通用api
name() // 返回列名
type() // 返回列的数据类型,比如LOCAL_DATE
size() // 返回列的长度
isEmpty() // 返回列是否为空
first(n) and last(n) // 返回列前/后n个数
max() and min() // 返回列的最大值/最小值
top(n) and bottom(n) // 返回n个最大/最小的数
print() // 返回列的字符串类型,用于输出
copy() // 复制一份新列
unique() // 返回列中的元素并只出现一次
countUnique() // 返回列中元素的种类
void sortAscending() // 升序排列
void sortDescending() // 降序佩列
append(otherColumn) // 将其他列添加到这个列后面
removeMissing() // 返回去除missing元素后的列
3.1.4 筛选
3.1.4.1 筛选出想要的列
筛选可以说是最重要的操作之一,它可以帮助我们选出我们想要的元素。以下面这个列为例:
double[] values = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
DoubleColumn column = DoubleColumn.create("column name", values);
Column: column name
1
2
3
4
5
6
7
8
9
10
筛选的第一步操作是创建一个表达式,比如我想筛选出所有大于5的数:
Selection limit = column.isGreaterThan(5);
然后就可以用where(Selection)
函数进行筛选:
DoubleColumn column_new = column.where(limit);
Column: column name
6
7
8
9
10
Tablesaw提供了非常多的表达式,几乎可以满足我们所有的需求:
对于DateColumn
和DateTimeColumn
这种时间相关的列而言,他们有一些特殊的表达式:
它可以帮助我们筛选出我们想要的日期,同时我们也可以通过先获取日期列的年/月/日/时/分/秒来得到一个新的列,再对列进行筛选。比如我想筛选出所有凌晨6点-7点的时间:
datetimecolumn.hour().isEqualTo(6);
列筛选是表格筛选的基础,后面还会继续讲解如何进行表格筛选。
3.1.4.2 有条件的编辑数据
以下面这个列为例:
double[] values = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
DoubleColumn column = DoubleColumn.create("column name", values);
比如我们想替换所有大于5的数为100,那么可以:
Selection limit = doublecolumn.isGreaterThan(5);
doublecolumn.set(limit, 100.0);
比如我们可以将所有缺失值设置为平均值:
double avg = doubleColumn.mean();
doubleColumn.set(doubleColumn.isMissing(), avg)
3.1.5 输出列
将列输出到终端显示:
System.out.println(doublecolumn.print());
3.2 表格操作
Tablesaw有大量创建、查询、操作、显示和保存表的方法,而且对表的许多操作都会返回其他表。例如,当您要求一个表描述其结构时,它会返回一个包含列名、类型和顺序的新表。
3.2.1 创建表格(导入文件)
/*方式一:添加列到表格中*/
Table t = Table.create("name", column1, column2, column3...)
//比如:
double[] values1 = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
DoubleColumn column1 = DoubleColumn.create("column1", values1);
double[] values2 = {
2, 1, 4, 4, 5, 6, 6, 1, 8, 4};
DoubleColumn column2 = DoubleColumn.create("column2", values2);
/*方式二:从文件中导入*/
Table t = Table.read().csv("myFile.csv");
当我们想从文件中导入表格时,我建议采用以下方法:
Table.read().file(File file);
Table.read().file(String path);
采用这种方式可以既可以导入.csv
格式的文件,也可以导入.xlsx
和.xls
格式的文件,但是这种方式不能指定导入文件的sheet,如果想要指定sheet,采用下面这种方法:
Table cap = Table.read().usingOptions(XlsxReadOptions
.builder(String path)
.sheetIndex(String sheet));
3.2.2 添加、删除和选择列
3.2.2.1 添加列
可以使用向表中添加一列或多列addColumns()
方法:
t.addColumns(aColumn...)
还可以通过提供索引来指定在特定位置插入列:
t.addColumn(3, aColumn);
需要注意的是,新添加的列必须为空,或者与表中的其他列具有相同数量的元素。
3.2.2.2 删除列
要删除一列或多列:
t.removeColumns(int... columnindexes)
t.removeColumns(String... columnnames)
或者指定想要保存的列,删除其他列,但是这种操作会在原列上进行,如果想要选择某几列而不改变原始数据,建议使用下面的选择列:
t.retainColumns(int... columnindexes)
t.retainColumns(String... columnnames)
3.2.2.3 选择列
当前官方文档中选择列给的是select()
函数,但是我建议使用selectColumns()
,因为前者不能通过指定index来选择列,而后者既可以用名称选择也可以用index选择:
Table t2 = t.selectColumns("column1");
Table t2 = t.selectColumns(0);
也可以通过在当前表格中指定不需要的列来创建新表格,这可能会节省一些键入时间,同样这个函数也可以用名称和index来指定列:
Table t2 = t.rejectColumns("column1");
Table t2 = t.rejectColumns(0);
如果只选择一列,通常需要将返回的列转换为更具体的类型。例如:
DoubleColumn dc = t.doubleColumn();
3.2.3 拼接表格
拼接表格有两种形式,一种是横向拼接,也就是行数相同,增加列数;零一周是纵向拼接,也就是列数相同,增加行数。
/*1. 横向组合*/
Table result = t.concat(t2);
/*2. 纵向组合*/
Table result = t.append(t2);
需要注意的是,横向拼接时两个表格的列名不能有重复,纵向拼接时对应列的列名必须相同。
3.2.4 筛选
筛选是在列筛选的基础上进行的,我们以下面这个表格为例:
LocalDate currentdate = LocalDate.of(Integer.parseInt("2022"), 1, 1);
List<LocalDate> date_list = new ArrayList<LocalDate>();
for(int d=0;d<10;d++)
{
date_list.add(currentdate.plusDays(d));
}
DateColumn date = DateColumn.create("Time", date_list);
double[] values = {
1, 2, 3, 4, 5,6,7,8,9,10};
DoubleColumn value = DoubleColumn.create("value", values);
Table t = Table.create("a",date,value);
a
Time | value |
------------------------
2022-01-01 | 1 |
2022-01-02 | 2 |
2022-01-03 | 3 |
2022-01-04 | 4 |
2022-01-05 | 5 |
2022-01-06 | 6 |
2022-01-07 | 7 |
2022-01-08 | 8 |
2022-01-09 | 9 |
2022-01-10 | 10 |
这里将筛选出2022年1月5日以后的数据。
筛选的第一步是选择我们想要筛选的列:
DateColumn date_column = t.dateColumn(0);
第二步是创建一个约束的表达式:
Selection limit = date_column.dayOfMonth().isGreaterThan(5);
第三步就可以用where()
函数进行筛选了:
Table t2 = t.where(limit);
a
Time | value |
------------------------
2022-01-06 | 6 |
2022-01-07 | 7 |
2022-01-08 | 8 |
2022-01-09 | 9 |
2022-01-10 | 10 |
筛选时我们也可以同时指定多个约束,比如我想要筛选出2022年1月5日以后并且value大于7的数据:
DateColumn date_column = t.dateColumn(0);
Selection limit1 = date_column.dayOfMonth().isGreaterThan(5);
DoubleColumn value_column = t.doubleColumn(1);
Selection limit2 = value_column.isGreaterThan(7);
Table t2 = t.where(limit1.and(limit2));
a
Time | value |
------------------------
2022-01-08 | 8 |
2022-01-09 | 9 |
2022-01-10 | 10 |
3.2.5 输出表格
将表格输出到终端显示:
System.out.println(t.print());
3.2.6 导出表格
table.write().csv("filename.csv");
表格只能导出为.csv
格式,后面我会写一下如何利用EasyExcel库将.csv
文件另存为.xlsx
中的某个sheet当中。
四. 最后
本文介绍了Tablesaw中的一些常用的基本操作,这些操作基本上能满足我们工作中的大部分需求,如果有其他需要可以去官网上查找对应的方法。总而言之Tablesaw是一个非常强大的数据处理库,但是也有一些不足之处,比如无法导出.xlsx
格式的文件。目前这个库应该还在不断完善当中,期待Tablesaw能够实现更多的功能!