刚上手R一个月,前两天为了交作业实现了极大无关组的求解,看网上并没有相关的代码所以分享一下。不足之处还有很多,希望各位大佬多多指教~
求解的大体思想就是化阶梯形,并且把每个阶梯的第一个元素的索引取出,利用索引得到原矩阵的一组极大无关组,验证是否线性无关只需要利用索引得到化为阶梯形后的子矩阵,子矩阵的秩是否为Min{行秩,列秩}
求解方法改进了一下选取列主元的高斯消去法,在其基础上为列主元的坐标定位指针[i, j],这样可以判断对该列进行高斯消去之后,下一列的主元位置和该列的主元位置,是在同一行还是在同一对角线上。倘若这两列线性相关则在同一行平移,若线性无关则对角线移动。
先简单介绍一下列主元高斯消元法,估计高斯看了棺材板会盖不住的。
在化阶梯形的过程中,比如从A[1, 1](不等于0)开始,将A[i, 1](i = 2, 3, 4....)的元素都化为0,这个过程就是在实现高斯消元。在消元的过程中,被用来消其他元素的那个元素叫做主元。而列主元的高斯消去法指的是每一列消元时,都选择本列绝对值最大的元素作为主元,并把那一行换到指针所在的位置。
为什么在列主元的高斯消去法里没有提指针的事请呢?因为它常用来实现n阶方阵的LU分解,指针默认方向是对角线,不用考虑横向平移的过程。
话不多说分享代码~
清空变量,导入数据清洗包dplyr
rm(list = ls())
library(dplyr)
定义行交换函数
# Reorder rows
rarrange = function(dtf, i1, i2){
dtf.i1 = dtf[i1, ]
dtf[i1, ] = dtf[i2, ]
dtf[i2, ] = dtf.i1
return(dtf)
}
主题函数部分,tg.tick是主元所在的行标,貌似which可以直接获取行标行交换更方便
(为了逻辑而放弃了美观,在函数体里加了注释,原谅一只菜鸡)
# Function
MLIG = function(mtx){
mdtf = as.data.frame(mtx)
i = 1
j = 1
tg.tick = i
m = dim(mdtf)[1]
n = dim(mdtf)[2]
index = NA
while ((i <= (m-1)) & (j <= n)){
colmax = mdtf[i, j]
# Find column principal and row.numbers it is in
for (t in (i+1) : m){
if (abs(as.numeric(mdtf[t, j])) > abs(as.numeric(colmax))){
colmax = abs(as.numeric(mdtf[t, j]))
tg.tick = t
}else{
tg.tick = i
}
}
# If column principal not equal to mdtf[i, j], no arrange operations
if (as.numeric(colmax) != mdtf[i, j]){
mdtf = rarrange(mdtf, i, tg.tick)
}else{}
# If column principal not equal to zero
if (colmax != 0){
for (t in (i+1):m){
k = mdtf[t, j] / mdtf[i, j]
mdtf[t, j:n] = mdtf[t, j:n] - mdtf[i, j:n]*k
}
index = c(index, j)
i = i + 1
j = j + 1
}else{
j = j + 1
}
}
index = na.omit(index)
result.dtf = select(as.data.frame(mtx), index)
check.dtf = mdtf
return(list(result.dtf = result.dtf, check.dtf = check.dtf))
}
用两个矩阵检验效果
# Effect test
MLIG(matrix(1:24, 4, 6))
MLIG(matrix(sample(1:10, 30, replace = T), 5, 6))
运行结果为
> MLIG(matrix(1:24, 4, 6))
$result.dtf
V1 V2
1 1 5
2 2 6
3 3 7
4 4 8
$check.dtf
V1 V2 V3 V4 V5 V6
1 4 8 12 16 20 24
2 0 3 6 9 12 15
3 0 0 0 0 0 0
4 0 0 0 0 0 0
> MLIG(matrix(sample(1:10, 30, replace = T), 5, 6))
$result.dtf
V1 V2 V3 V4
1 4 5 6 7
2 9 7 3 8
3 7 2 7 9
4 9 4 4 9
5 7 3 8 4
$check.dtf
V1 V2 V3 V4 V5 V6
1 4 5.00 6.00000 7.000000 6.000000 4.0000000
2 0 -4.25 -10.50000 -7.750000 -4.500000 -5.0000000
3 0 0.00 13.17647 9.058824 6.647059 7.9411765
4 0 0.00 0.00000 -5.812500 -1.316964 0.7098214
5 0 0.00 0.00000 0.000000 -5.222734 -1.4562212