当前位置: 首页 > 工具软件 > Tablesaw > 使用案例 >

Java数据可视化库Tablesaw的简单使用

符棋
2023-12-01

项目源码链接: Tablesaw
Java是一种很棒的语言,但它并不是为数据分析而设计的。通过Tablesaw,我们可以轻松的使用Java进行数据分析。

| @Author:TTODS

配置

  1. Tablesaw需要Java8或更新的版本。
  2. 使用Maven导入包。
<dependency>
   <groupId>tech.tablesaw</groupId>
   <artifactId>tablesaw-core</artifactId>
   <version>LATEST</version>
</dependency>

表和列

Tablesaw整个都是关于表格的,而表格又是由列组成的,所以我们的学习先从列开始。

一个Column是一个被命名的,一维数据集,它可能是一个Table的一部分,也可能不是。一个Column中的数据必须是同一种类型。

创建一个数据列

使用DoubleColumn.create(String name,double ... arr)方法来创建一个元素类型为double的column;
根据包含元素类型的不同,还有IntColumn,StringColumn等。


 double[] numbers = {1,2,3,4};
 DoubleColumn nc = DoubleColumn.create("nc",numbers);
 //    DoubleColumn nc = DoubleColumn.create("nc",1,2,3,4); 这样也是可以的
 System.out.println(nc.print());

程序输出:

Column: nc
1
2
3
4
获取数列中的某个数据

使用 nc.get(int index)方法来获取column某个元素,index从0开始。

 // 创建数据列
 double[] numbers = {1,2,3,4};
 DoubleColumn nc = DoubleColumn.create("nc",numbers);
 // index为2,所以获取到nc中的第三个元素
 Double three = nc.get(2);
 System.out.println(three);

程序输出:

3.0
columnar operations(柱状运算)

Tablesaw中有很多针对一列数据的运算,如下面的multiply(Number value)是原来列中的每个元素都乘以value。

 // 创建数据列
 double[] numbers = {1,2,3,4};
 DoubleColumn nc1 = DoubleColumn.create("nc",numbers);
 System.out.println(nc1.print());
 // 使用multiply(Number value)是原来列中的每个元素都乘以value
 // 这个方法并不会修改nc,而是返回一个新的Column对象nc1,nc1的列名为[nc列名*value],我们可以使用 setName(String name),设置列名;
 DoubleColumn nc2 = nc1.multiply(8);
 // nc1.setName("nc2");
 System.out.println(nc2.print());

程序输出:

Column: nc
1
2
3
4

Column: nc * 8.0
8
16
24
32
Selections(选择项)

Selections被用来筛选表和列。我们对一个Column对象使用形如isLessThan(aNumber)方法来附加筛选条件,就可以生成一个Selection对象,一个Selection对象包含一个有序的int类型的集合,该集合包含了Column对象中满足设定条件的元素的索引。

 // 创建数据列
 double[] numbers = {1,2,3,4};
 DoubleColumn nc1 = DoubleColumn.create("nc",numbers);

 // 使用isLessThan(double value)方法 获取筛选出nc中小于3的元素的Selection对象
 Selection lessThanThreeSelection = nc1.isLessThan(3);
 //A selection maintains an ordered set of ints that can be used to eval rows from a table or column
 System.out.println(Arrays.toString(lessThanThreeSelection.toArray()));

程序输出:

[0, 1]

使用where(Selection selection)方法,获取经过指定selection筛选后的Column或Table

 DoubleColumn nc2 = nc1.where(lessThanThreeSelection);
 System.out.println(nc2.print());

程序输出:

Column: nc
1
2

组合过滤器

 DoubleColumn nc3 = nc1.where(nc1.isGreaterThan(1).and(nc1.isLessThan(3)));
 System.out.println(nc3.print());

程序输出:

Column: nc
2

通过index选择

 DoubleColumn nc4 = nc1.where(Selection.with(1, 3));
 System.out.println(nc4.print());
 DoubleColumn nc5 = nc1.where(Selection.withRange(1, 3));
 System.out.println(nc5.print());

程序输出:

Column: nc
2
4

Column: nc
2
3
Map functions

Map functions是一些定义在columns上的方法,它们返回一个新的Columns,
之前的 Column multiply(Number value)方法就是一个有一个标量参数的map function
我们也可以使用multiply(NumberColumn numberColumn)的方法,来是两个column中的值对应相乘

 DoubleColumn nc1 = DoubleColumn.create("nc",new double[]{1,2,3,4,5});
 DoubleColumn nc2 = DoubleColumn.create("nc1",new double[]{1,2,3,4,5});
 DoubleColumn nc3 = nc1.multiply(nc2);
 System.out.println(nc3.print());

程序输出:

Column: nc * nc1
1
4
9
16
25

Tablesaw针对各种Column类型内置了很多的map functions,下面是一些例子

 StringColumn s = StringColumn.create("sc", new String[] {"foo", "bar", "baz", "foobarbaz"});
 StringColumn s2 = s.copy();
 // 以下方法全部都是针对StringColumn中所有字符串进行的操作
 s2 = s2.replaceFirst("foo", "bar"); // 字符串替换
 s2 = s2.upperCase();                // 转化成大写
 s2 = s2.padEnd(5, 'x');             // 字符串的长度小于minlength(第一个参数)时,在字符串的尾部填充某字符,使其长度达到minlength
 s2 = s2.substring(1, 5);            // 获取[1,5)子串
 System.out.println(s2.print());

程序输出:

Column: sc[repl][ucase][pad][sub]
ARxx
ARxx
AZxx
ARBA
Reduce (aggregate) functions: Summarizing a column(汇总功能)

有时我们想计算一些值从某种意义上总结一列中的数据,汇总函数就是用来做这个的。

DoubleColumn nc1 = DoubleColumn.create("nc",new double[]{1,2,3,4,5});
double max = nc1.max();     // 列中的最大值
System.out.println(max);

double min = nc1.min();     //  列中的最小值
System.out.println(min);

double sum = nc1.sum();     // 最大值
System.out.println(sum);

double stdDev = nc1.standardDeviation();    // 标准差
System.out.println(stdDev);

程序输出:

5.0
1.0
15.0
1.5811388300841898

一个Table是一个被命名的columns的容器,虽然缺失值是允许的,但是table中所有的column的元素数量应该一样。
一个Table可以包含任何类型的columns组合。

创建Table
String[] animals = {"bear", "cat", "giraffe"};
double[] cuteness = {90.1, 84.3, 99.7};

 // 使用create(String name)方法创建Table对象,使用addColumns(Column<?>...cols)方法向表中添加列
 Table cuteAnimals = Table.create("Cute Animals").addColumns(
         StringColumn.create("Animal types", animals),
         DoubleColumn.create("rating", cuteness));

 System.out.println(cuteAnimals.print());

程序输出:

       Cute Animals        
 Animal types  |  rating  |
---------------------------
         bear  |    90.1  |
          cat  |    84.3  |
      giraffe  |    99.7  |
导入数据

很多时候我们会直接从csv文件中导入数据,使用下面的语句可以很方便的从csv文件中读取一个Table对象,Tablesaw可以很好的猜测出每一列的类型,当它猜错类型或者是我们想要提高性能的时候可以指明类型。

 Table bushTable = Table.read().csv("data/bush.csv");
 System.out.println(bushTable.print());

程序输出:

              bush.csv               
    date     |  approval  |   who   |
-------------------------------------
 2004-02-04  |        53  |    fox  |
 2004-01-21  |        53  |    fox  |
 2004-01-07  |        58  |    fox  |
 2003-12-03  |        52  |    fox  |
 2003-11-18  |        52  |    fox  |
 2003-10-28  |        53  |    fox  |
 2003-10-14  |        52  |    fox  |
 2003-09-23  |        50  |    fox  |
 2003-09-09  |        58  |    fox  |
 2003-08-12  |        57  |    fox  |
        ...  |       ...  |    ...  |
 2001-12-03  |        81  |  zogby  |
 2001-10-23  |        78  |  zogby  |
 2001-09-14  |        82  |  zogby  |
 2001-08-28  |        50  |  zogby  |
 2001-07-26  |        47  |  zogby  |
 2001-06-24  |        51  |  zogby  |
 2001-04-23  |        52  |  zogby  |
 2001-03-27  |        52  |  zogby  |
 2001-02-27  |        53  |  zogby  |
 2001-02-09  |        57  |  zogby  |
浏览Tables

Tablesaw提供了一些方法,让帮助我们了解新数据集的结构,形状等信息。

  • Table的结构(列名,列类型)
 Table bushTable = Table.read().csv("data/bush.csv");
 System.out.println(bushTable.structure());

程序输出:

          Structure of bush.csv          
 Index  |  Column Name  |  Column Type  |
-----------------------------------------
     0  |         date  |   LOCAL_DATE  |
     1  |     approval  |      INTEGER  |
     2  |          who  |       STRING  |
  • Table的形状(rows*cols)
 System.out.println(bushTable.shape());

程序输出:

323 rows X 3 cols
  • 显示前3行数据
 System.out.println(bushTable.first(3));

程序输出:

             bush.csv              
    date     |  approval  |  who  |
-----------------------------------
 2004-02-04  |        53  |  fox  |
 2004-01-21  |        53  |  fox  |
 2004-01-07  |        58  |  fox  |
  • 显示后3行数据
 System.out.println(bushTable.last(3));

程序输出:

              bush.csv               
    date     |  approval  |   who   |
-------------------------------------
 2001-03-27  |        52  |  zogby  |
 2001-02-27  |        53  |  zogby  |
 2001-02-09  |        57  |  zogby  |
  • Table的toString()方法也表示为上面那种表格的形式
 Table bushTable = Table.read().csv("data/bush.csv");
 // 默认只显示20rows,其他数据会省略;
 System.out.println(bushTable.toString());
 // 我们可以使用printAll()来打印所有的数据
 System.out.println(bushTable.printAll());
 // 也可以使用print(int rowLimit)来指定打印的行数
 System.out.println(bushTable.print(100));
处理表中的column
 //构造表
 Table table = Table.create("table").addColumns(IntColumn.create("col1", 1, 2, 3, 4, 5),
 IntColumn.create("col2", 2, 4, 6, 8, 0), IntColumn.create("col3", 3, 6, 9, 12, 13));
 System.out.println(table);
 // 移除列
 // 移除 名字为"col1"的列
 table.removeColumns("col1");
 System.out.println(table);
 // 只保留 名字为"col2"的列
 table.retainColumns("col2");
 System.out.println(table);

 // 添加列
 table.addColumns(IntColumn.create("col4", 4, 8, 12, 16, 20));
 System.out.println(table);

程序输出:

      table      
 col2  |  col3  |
-----------------
    2  |     3  |
    4  |     6  |
    6  |     9  |
    8  |    12  |
    0  |    13  |
 table  
 col2  |
--------
    2  |
    4  |
    6  |
    8  |
    0  |
      table      
 col2  |  col4  |
-----------------
    2  |     4  |
    4  |     8  |
    6  |    12  |
    8  |    16  |
    0  |    20  |
从table中获取特定类型的column
 Table studentTable = Table.create("student").addColumns(IntColumn.create("id", 20200001, 20200002, 20200003, 20200004, 20200005),
                StringColumn.create("name", "Jim", "Bob", "John", "lily", "lucy"));

 // column(String colName)方法,通过列名获取指定列,不区分大小写
 Column<?> idCol1 = studentTable.column("id");
 System.out.println(idCol1.print());

 //  column(int colIndex)方法,通过索引获取指定列,索引从0开始
 Column<?> idCol2 = studentTable.column(0);
 System.out.println(idCol2.print());
 //        System.out.println(idCol1 == idCol2); // true

 // 上面的方法返回的都是Column<?>类型,必要时需要转换成特定的类型
 // 1.强制类型转换
 IntColumn idCol3 = (IntColumn) studentTable.column("id");
 // 2.使用numberColumn(),stringColumn()等方法
 NumericColumn<?> idColumn = studentTable.numberColumn("id");

程序输出:

Column: id
20200001
20200002
20200003
20200004
20200005

Column: id
20200001
20200002
20200003
20200004
20200005
处理行
  • 删除行
 Table studentTable = Table.create("student").addColumns(IntColumn.create("id", 20200001, 20200001, 20200002, 20200003, 20200004, 20200005),
                 StringColumn.create("name", "Jim", "Jim", "Bob", "John", "lily", "lucy"));
 System.out.println(studentTable.print());
 // drop...()方法不在原表上修改,而是先创建一个和原表结构一样的空表,然后把不需要删除的行放到新的而表中,然后返回新的表。
 Table table1 = studentTable.dropDuplicateRows();
 System.out.println(table1.print());

 Table table2 = studentTable.dropWhere(studentTable.numberColumn(0).isLessThan(20200003));
 System.out.println(table2);

程序输出:

       student       
    id     |  name  |
---------------------
 20200001  |   Jim  |
 20200001  |   Jim  |
 20200002  |   Bob  |
 20200003  |  John  |
 20200004  |  lily  |
 20200005  |  lucy  |
       student       
    id     |  name  |
---------------------
 20200001  |   Jim  |
 20200002  |   Bob  |
 20200003  |  John  |
 20200004  |  lily  |
 20200005  |  lucy  |
        student       
    id     |  name  |
---------------------
 20200002  |   Bob  |
 20200005  |  lucy  |
 20200001  |   Jim  |
  • 增加行
 // 修改原表
 studentTable.addRow(0, studentTable);
  • 随机抽样
 Table table3 = studentTable.sampleN(3);
 System.out.println(table3.print());

程序输出:

       student       
    id     |  name  |
---------------------
 20200002  |   Bob  |
 20200005  |  lucy  |
 20200001  |   Jim  |
  • 我们也可以对表中的行执行任意的操作
 // 遍历表中的行,并执行操作
 for (Row r : studentTable) {
     System.out.println("学号:" + r.getString(1) + ":" + r.getString(1));
 }

 // 另外一种实现形式
 studentTable.stream().forEach(row -> {
     System.out.println("学号:" + row.getString(1) + ":" + row.getString(1));
 });
table排序
 Table studentTable = Table.create("student").addColumns(IntColumn.create("id", 20200001,20200002, 20200003, 20200004, 20200005),
 StringColumn.create("name", "Jim", "Bob", "John", "lily", "lucy"));
 // 升序
 studentTable = studentTable.sortOn("id", "name");// or sortAscendingOn("id","name");
 System.out.println(studentTable.print());

 // 降序
 studentTable = studentTable.sortDescendingOn("id");
 System.out.println(studentTable);

程序输出:

       student       
    id     |  name  |
---------------------
 20200001  |   Jim  |
 20200002  |   Bob  |
 20200003  |  John  |
 20200004  |  lily  |
 20200005  |  lucy  |
       student       
    id     |  name  |
---------------------
 20200005  |  lucy  |
 20200004  |  lily  |
 20200003  |  John  |
 20200002  |   Bob  |
 20200001  |   Jim  |
筛选

查询filter(过滤器)可以使用逻辑运算符or,and,not来组合,它们都在QuerySupport中实现,所以在使用前要先导入:

import static tech.tablesaw.api.QuerySupport.and;
import static tech.tablesaw.api.QuerySupport.or;
import static tech.tablesaw.api.QuerySupport.not;
Table studentTable = Table.create("student").addColumns(IntColumn.create("id", 20200001, 20200002, 20200003, 20200004, 20200005),
               StringColumn.create("name", "Jim", "Bob", "John", "lily", "lucy"),
               IntColumn.create("age", 18, 18, 17, 16, 16));

 Table result = studentTable.where(and(t -> t.numberColumn("id").isGreaterThan(20200001),
         t -> t.numberColumn("age").isEqualTo(18)));
 System.out.println(result);

程序输出:

           student           
    id     |  name  |  age  |
-----------------------------
 20200002  |   Bob  |   18  |

- THE END -
 类似资料: