一. 前言

Tablesaw是一款Java的数据可视化库,主要包括两部分:

  1. 数据解析库,主要用于加载数据,对数据进行操作(转化,过滤,汇总等),类比Python中的Pandas库;
  2. 数据可视化库,将目标数据转化为可视化的图表,类比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提供了非常多的表达式,几乎可以满足我们所有的需求:

对于DateColumnDateTimeColumn这种时间相关的列而言,他们有一些特殊的表达式:

它可以帮助我们筛选出我们想要的日期,同时我们也可以通过先获取日期列的年/月/日/时/分/秒来得到一个新的列,再对列进行筛选。比如我想筛选出所有凌晨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能够实现更多的功能!