在gonum/mat中还有许多有用的矩阵处理相关的函数,下面是一些例子:
初始化一个全0的矩阵
matrix1 := mat.NewDense(6, 9, nil)
fmt.Printf("%v\n", mat.Formatted(matrix1))
// NewDense(r, c int, data []float64) *Dense 参数说明:
// NewDense creates a new Dense matrix with r rows and c columns. If data == nil,
// a new slice is allocated for the backing slice. If len(data) == r*c, data is
// used as the backing slice, and changes to the elements of the returned Dense
// will be reflected in data. If neither of these is true, NewDense will panic.
// NewDense will panic if either r or c is zero.
// The data must be arranged in row-major order, i.e. the (i*c + j)-th
// element in the data slice is the {i, j}-th element in the matrix.
输出结果:
⎡0 0 0 0 0 0 0 0 0⎤
⎢0 0 0 0 0 0 0 0 0⎥
⎢0 0 0 0 0 0 0 0 0⎥
⎢0 0 0 0 0 0 0 0 0⎥
⎢0 0 0 0 0 0 0 0 0⎥
⎣0 0 0 0 0 0 0 0 0⎦
生成随机矩阵
data := make([]float64, 24)
for i := range data {
data[i] = rand.NormFloat64()
}
a := mat.NewDense(6, 4, data)
fmt.Printf("%v\n", mat.Formatted(a))
输出:
⎡ -1.233758177597947 -0.12634751070237293 -0.5209945711531503 2.28571911769958⎤
⎢ 0.3228052526115799 0.5900672875996937 0.15880774017643562 0.9892020842955818⎥
⎢ -0.731283016177479 0.6863807850359727 1.585403962280623 0.8382059044208106⎥
⎢ 1.2988408475174342 0.5273583930598617 0.7324419258045132 -1.0731798210887524⎥
⎢ 0.7001209024399848 0.4315307186960532 0.9996261210112625 -1.5239676725278932⎥
⎣-0.31653724289408824 1.8894642062634817 1.1007291937500208 -0.9927431907514367⎦
单独设置行或列的数据
我们用mat.Dense类型的成员函数SetRow、SetCol、Set来单独设置数据。
a := mat.NewDense(2, 3, []float64{
1, 2, 3,
4, 5, 6})
fmt.Printf("%v\n\n", mat.Formatted(a))
a.SetRow(1, []float64{7, 8, 9})
fmt.Printf("%v\n\n", mat.Formatted(a))
a.SetCol(2, []float64{10, 15})
fmt.Printf("%v\n\n", mat.Formatted(a))
a.Set(1, 2, float64(50))
fmt.Printf("%v\n\n", mat.Formatted(a))
输出:
⎡1 2 3⎤
⎣4 5 6⎦
⎡1 2 3⎤
⎣7 8 9⎦
⎡ 1 2 10⎤
⎣ 7 8 15⎦
⎡ 1 2 10⎤
⎣ 7 8 50⎦
克隆与复制矩阵
克隆
矩阵的克隆是指获得一个与源矩阵完全相同的新矩阵,可以使用mat.Dense类型的成员函数CloneFrom来实现。
a := mat.NewDense(2, 3, []float64{
1, 2, 3,
4, 5, 6})
fmt.Printf("%v\n\n", mat.Formatted(a))
b := mat.NewDense(3, 2, []float64{
8, 8,
8, 8,
6, 6})
fmt.Printf("%v\n\n", mat.Formatted(b))
b.CloneFrom(a)
fmt.Printf("%v\n\n", mat.Formatted(a))
fmt.Printf("%v\n\n", mat.Formatted(b))
输出结果
⎡1 2 3⎤
⎣4 5 6⎦
⎡8 8⎤
⎢8 8⎥
⎣6 6⎦
⎡1 2 3⎤
⎣4 5 6⎦
⎡1 2 3⎤
⎣4 5 6⎦
可以看出,不管矩阵b的形态,克隆完的新矩阵将同源矩阵(矩阵a)的形态和数据一模一样。
复制
而将一个矩阵中的数据复制到另一个矩阵可以用mat.Dense的成员函数Copy来实现。
a := mat.NewDense(2, 3, []float64{
1, 2, 3,
4, 5, 6})
fmt.Printf("%v\n\n", mat.Formatted(a))
b := mat.NewDense(3, 2, []float64{
8, 8,
8, 8,
6, 6})
fmt.Printf("%v\n\n", mat.Formatted(b))
b.Copy(a)
fmt.Printf("%v\n\n", mat.Formatted(a))
fmt.Printf("%v\n\n", mat.Formatted(b))
输出
⎡1 2 3⎤
⎣4 5 6⎦
⎡8 8⎤
⎢8 8⎥
⎣6 6⎦
⎡1 2 3⎤
⎣4 5 6⎦
⎡1 2⎤
⎢4 5⎥
⎣6 6⎦
可以看出,复制矩阵数据的方式是逐行逐列进行数据复制,当两个矩阵的行数和列数不同时,超出的部分将被丢弃,缺少的部分将不动。由于矩阵a比b多一列,所以a中第3列的数据都被丢弃了;而矩阵b比a多出来的第3行的数据则都没有动。
改变矩阵形态:扩张与切片
如果要扩张矩阵,可以使用mat.Dense类型的Grow成员函数,类似下面的代码:
a := mat.NewDense(2, 3, []float64{
1, 2, 3,
4, 5, 6})
b := a.Grow(2, 2)
fmt.Printf("%v\n\n", mat.Formatted(b))
将得到如下所示的扩展了2行和2列的新矩阵:
⎡1 2 3 0 0⎤
⎢4 5 6 0 0⎥
⎢0 0 0 0 0⎥
⎣0 0 0 0 0⎦
反过来如果要裁剪某个矩阵则要对该矩阵做切片,此时应使用mat.Dense类型的Slice成员函数。例如要将一个2×3的矩阵右侧的2×2的子矩阵切分出来,可以用下面的代码:
a := mat.NewDense(2, 3, []float64{
1, 2, 3,
4, 5, 6})
b := a.Slice(0, 2, 1, 3)
fmt.Printf("%v\n\n", mat.Formatted(b))
// Slice 参数说明
// (m *Dense) Slice(i, k, j, l int) Matrix
// Slice returns a new Matrix that shares backing data with the receiver.
// The returned matrix starts at {i,j} of the receiver and extends k-i rows
// and l-j columns. The final row in the resulting matrix is k-1 and the
// final column is l-1.
// Slice panics with ErrIndexOutOfRange if the slice is outside the capacity
// of the receiver.
Slice成员函数,它的4个参数中的第1个和第3个分别对应要截取的行数的起始索引和列数的起始索引,而第2个和第4个参数则是要截取的行数的结尾索引再加上1的值和列数的结尾索引再加上1的值。因此,我们传递的4个参数值就表示从矩阵a中的第1行第2列开始,截取到第2行第3列,注意结尾的索引都应加1,这点容易忘记。
本段代码运行后切片出来的矩阵是:
⎡2 3⎤
⎣5 6⎦
矩阵的合并
横向合并
矩阵的横向合并使用mat.Dense类型的Augment成员函数,两个矩阵只有在行数相同时才能进行横向合并。
a := mat.NewDense(2, 3, []float64{
1, 2, 3,
4, 5, 6})
b := mat.NewDense(2, 2, []float64{
8, 8,
8, 8})
var c mat.Dense
c.Augment(a, b)
fmt.Printf("%v\n\n", mat.Formatted(&c))
输出结果
⎡1 2 3 8 8⎤
⎣4 5 6 8 8⎦
纵向合并
相应地,矩阵的纵向合并是使用mat.Dense类型的Stack成员函数,两个矩阵只有在列数相同时才能进行纵向合并。
a := mat.NewDense(2, 3, []float64{
1, 2, 3,
4, 5, 6})
b := mat.NewDense(3, 3, []float64{
8, 8, 8,
8, 8, 8,
8, 8, 8})
var c mat.Dense
c.Stack(a, b)
fmt.Printf("%v\n\n", mat.Formatted(&c))
输出结果
⎡1 2 3⎤
⎢4 5 6⎥
⎢8 8 8⎥
⎢8 8 8⎥
⎣8 8 8⎦