java 矩阵运算_java矩阵计算及其在统计中的应用(一)

本文介绍了Java中的Colt和Commons-Math3库在矩阵计算中的应用,包括矩阵构造、赋值、索引、矩阵运算等方面,并通过实例比较了两者在性能和使用上的差异。重点讲解了Colt库的特性,如 DenseDoubleMatrix2D 和 SparseDoubleMatrix2D 的实现,以及矩阵乘法、逐元素计算等操作。
摘要由CSDN通过智能技术生成

该文介绍了java colt和commons-math3的一些矩阵计算API,并且使用colt库简单实现了基于法方程组法的最小二乘法,结构方程模型的梯度下降参数估计,广义混合效应模型(多层广义线性模型)的MCMC参数估计,实现和测试代码链接inuyasha11/stats

java矩阵计算概况

因为项目迁移需求,需要用java编写一些统计计算库。上网搜索了几个java矩阵库,找到了两个主流的,colt和commons-math3,colt库是CERN(欧洲核子研究组织)主导开发的,上次更新好像是10年前(?),所幸代码能支持java8,commons-math3一看名字就知道,系出apache软件基金会,里面除了矩阵库,还有其他的数学和统计方法,例如kmeans,遗传算法。这个两个库尝试了之后发现,真是难用,除了因为java缺乏操作符重载外,这两库API太少,很多轮子需要自己造,同时单线程速度也比底层调用blas,lpack的那些C++、python库慢,唯一的优点是纯java,可以很方便的多线程开发和后端系统对接,但是现在都搞微服务,谁还把计算模块嵌入业务模块啊。不过既然尝试,咱也写写使用介绍和心得吧,重点介绍下colt,稍微介绍下commons-math3。

矩阵构造

colt和commons-math3均支持两种形式的矩阵构造,dense矩阵和稀疏矩阵

对于dense矩阵,colt的实现是一维数组,commons-math3是二维数组,当矩阵元素大于4096的时候,commons-math3的dense矩阵工厂方法会创建BlockRealMatrix实例,BlockRealMatrix顾名思义,就是将矩阵分块存储,所以BlockRealMatrix虽然也是二维数组实现,但是数组的第一个索引仅仅是分块矩阵索引,第二个索引才是矩阵元素索引,本质上变成了和colt一样的一维数组实现。

对于稀疏矩阵,colt提供了稀疏矩阵类SparseDoubleMatrix2D,其存储矩阵元素的elements属性是一个hashmap,为了节省内存,colt自己实现了一个基于开放寻址方法的hashmap,在这个hashmap中,键为int类型,是矩阵的元素索引,值为double类型,是矩阵的元素值。当对稀疏矩阵set元素值的时候,如果元素值为0,则从hashmap中删除该元素的索引,若不为0,则在hashmap中存储键值对(索引,元素值),commons-math3的稀疏矩阵实现形式与colt类似,就不多赘述了。

colt和commoms-math3均支持通过传入矩阵的行数和列数构造初始化元素为0的矩阵

colt代码

import cern.colt.matrix.DoubleMatrix2D;

import cern.colt.matrix.impl.DenseDoubleMatrix2D;

DoubleMatrix2D mat = new DenseDoubleMatrix2D(3, 4);

System.out.println(mat.toString());

commons-math3代码

RealMatrix mat = new Array2DRowRealMatrix(4,4);

也可以通过传入二维数组构造矩阵

colt代码

double[][] matData = { {1d, 2d, 3d}, {4d, 5d, 6d}, {7d, 8d, 9d}};

DoubleMatrix2D mat = new DenseDoubleMatrix2D(matData);

System.out.println(mat.toString());

commons-math3代码

double[][] matData = { {1d, 2d, 3d}, {4d, 5d, 6d}, {7d, 8d, 9d}};

RealMatrix mat = new Array2DRowRealMatrix(matData);

也可以通过工厂模式创建矩阵实例

colt代码

DoubleFactory2D F = DoubleFactory2D.dense;

F.make(4,4);

这个工厂类还包含一些很有趣的静态方法,例如创建随机元素矩阵的方法random,合并两个矩阵的appendColumns方法和appendRows方法

DoubleFactory2D F = DoubleFactory2D.dense;

DoubleMatrix2D mat1 = F.random(10, 5);

DoubleMatrix2D mat2 = F.random(10, 3);

DoubleMatrix2D mat3 = F.appendColumns(mat1, mat2);

System.out.println(mat3);

commons-math3代码

RealMatrix mat = MatrixUtils.createRealMatrix(4, 4);

commons-math3的工厂方法会自动根据矩阵元素的大小创建Array2DRowRealMatrix类实例或BlockRealMatrix类实例,关于这两个类前面已经说明了一些情况,不多赘述了。

赋值和索引矩阵元素

colt

colt提供了get方法和getQuick方法读取矩阵中的单个元素值,还提供了set和setQuick方法设置矩阵中的单个元素值,get方法和getQuick方法的区别是get方法里加入了一些参数检查代码,set方法和setQuick方法同理,理论上getQuick和setQuick更快。

double[][] matData = { {1d, 2d, 3d}, {4d, 5d, 6d}, {7d, 8d, 9d}};

DoubleMatrix2D mat = new DenseDoubleMatrix2D(matData);

System.out.println(mat.get(0, 0));

mat.set(0, 0, 10d) ;

System.out.println(mat.get(0, 0));

commons-math3

commons-math3提供了getEntry和setEntry两个方法索引和赋值矩阵元素,内部实现和colt几乎一样

double[][] matData = { {1d, 2d, 3d}, {4d, 5d, 6d}, {7d, 8d, 9d}};

RealMatrix mat = new Array2DRowRealMatrix(matData);

double val = mat.getEntry(0, 0);

mat.setEntry(0, 0, val + 10d);

获得矩阵的行数和列数

colt代码

int rowSize = mat.rows();

int colSize = mat.rows();

commons-math3代码

int rowSize = mat.getRowDimension();

int colSize = mat.getColumnDimension();

复制矩阵

colt

在colt中,复制矩阵,只复制矩阵的形状,不复制元素,可以使用like方法

double[][] matData = { {1d, 2d, 3d}, {4d, 5d, 6d}};

DoubleMatrix2D mat1 = new DenseDoubleMatrix2D(matData);

DoubleMatrix2D mat2 = mat1.like();

System.out.println(mat2);

又复制矩阵的形状,又复制元素,可以使用copy方法

double[][] matData = { {1d, 2d, 3d}, {4d, 5d, 6d}};

DoubleMatrix2D mat1 = new DenseDoubleMatrix2D(matData);

DoubleMatrix2D mat2 = mat1.copy();

System.out.println(mat2);

commons-math3

commons-math3貌似只提供了copy方法,commons-math3的copy方法调用了System.arraycopy静态方法进行数组赋值

RealMatrix mat2 = mat1.copy();

矩阵赋值速度比较

运行100次取平均值,单位毫秒

equation?tex=%5Cbegin%7Barray%7D%7B%7Cc%7Cc%7C%7D%5C++%E7%9F%A9%E9%98%B5%E5%A4%A7%E5%B0%8F%26colt%26commons-math3%5C%5C++%5Chline++2000%2A2000%2615%2620%5C%5C+4000%2A4000%2653%26136%5C%5C+6000%2A6000%26189%26387++%5Cend%7Barray%7D

矩阵乘法

colt

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值