如何从 sprintf 打印 R 矩阵

How to print R matrix from sprintf

对于以下矩阵:

> mat
             [,1]          [,2]          [,3]
[1,] 8.326673e-17  5.551115e-17  5.551115e-17
[2,] 2.775558e-17  3.677614e-16 -5.551115e-17
[3,] 0.000000e+00 -2.775558e-17  5.551115e-17

考虑以下 sprintf

sprintf("proj: %s", mat)

输出为:

print(sprintf("proj: %s", mat))
[1] "proj: 8.32667268468867e-17"  "proj: 2.77555756156289e-17"
[3] "proj: 0"                     "proj: 5.55111512312578e-17"
[5] "proj: 3.67761376907083e-16"  "proj: -2.77555756156289e-17"
[7] "proj: 5.55111512312578e-17"  "proj: -5.55111512312578e-17"
[9] "proj: 5.55111512312578e-17"

我们想要的是与 mat 相同的输出,但

"proj: "

消息已添加。具体来说:

proj:             [,1]          [,2]          [,3]
[1,] 8.326673e-17  5.551115e-17  5.551115e-17
[2,] 2.775558e-17  3.677614e-16 -5.551115e-17
[3,] 0.000000e+00 -2.775558e-17  5.551115e-17

如何使用 sprintf 来实现?

UPDATE 来自 Sven 的回答,在这里尝试创建一个函数:

printmat <- function(mat) {
  out <- capture.output(mat)
  out[1] <- paste0("proj:", out[1])
  paste(out, collapse = "\n")
}

这里是输出:单行(最好像原来的 4 行):

print(printmat(mat))

[1] "proj:             [,1]          [,2]          [,3]\n[1,] 8.326673e-17  5.551115e-17  5.551115e-17\n[2,] 2.775558e-17  3.677614e-16 -5.551115e-17\n[3,] 0.000000e+00 -2.775558e-17  5.551115e-17"

另一个更新 来自 Richard Scriven 的不同答案使用 print.listof(list)。这是一个包含 capture.output 的函数。然而,这个解决方案的缺点是不允许灵活的消息:它被硬编码为 "proj":

printmat <- function(mat) {
  out <- capture.output(print.listof(list(proj = mat)))
}

这是输出:它是 close .. 但请注意我们没有选择将 "proj" 更改为其他内容:

   print(printmat(mat))

[1] "proj :"
[2] "             [,1]          [,2]          [,3]"
[3] "[1,] 8.326673e-17  5.551115e-17  5.551115e-17"
[4] "[2,] 2.775558e-17  3.677614e-16 -5.551115e-17"
[5] "[3,] 0.000000e+00 -2.775558e-17  5.551115e-17"
[6] ""

第三次更新 我添加了一个灵活的 "message/matrix name" 参数。但是 sprintf 将其添加到输出的每一行:

printmat <- function(msg, mat) {
  out <- capture.output(print.listof(list(mat)))
  sprintf("%s: %s", msg, out)
}

这是一个测试:

> print(printmat("mymat", mat))
[1] "mymat: Component 1 :"
[2] "mymat:              [,1]          [,2]          [,3]"
[3] "mymat: [1,] 8.326673e-17  5.551115e-17  5.551115e-17"
[4] "mymat: [2,] 2.775558e-17  3.677614e-16 -5.551115e-17"
[5] "mymat: [3,] 0.000000e+00 -2.775558e-17  5.551115e-17"
[6] "mymat:

那么有没有办法抑制sprintf每个行前加上消息?

这是 capture.output 的方法:

# an example matrix
mat <- matrix(rnorm(9), nrow = 3)

# standard print output
out <- capture.output(mat)
# modify first line
out[1] <- paste0("proj:", out[1])
# print modified version
cat(paste(out, collapse = "\n"))

输出:

proj:          [,1]       [,2]      [,3]
[1,] 0.8760935 -0.8395728 -1.569009
[2,] 0.2660100 -2.2364285 -1.872737
[3,] 0.4996019 -0.6997563 -2.136702

作为函数:

printmat <- function(mat) {
  out <- capture.output(mat)
  out[1] <- paste0("proj:", out[1])
  cat(paste(out, collapse = "\n"))
}


printmat(mat)

使用 sprintf(),您会将整个矩阵转换为字符,这使得以后访问它们的数值变得更加困难。

相反,您可以使用 listof class 然后您仍然可以访问所有数值。首先将矩阵(或多个矩阵)放入命名列表中。快速浏览一下它的外观。

m <- structure(c(8.326673e-17, 2.775558e-17, 0, 5.551115e-17, 3.677614e-16, 
-2.775558e-17, 5.551115e-17, -5.551115e-17, 5.551115e-17), .Dim = c(3L, 
3L))

print.listof(list(proj = m))
# proj :
#              [,1]          [,2]          [,3]
# [1,] 8.326673e-17  5.551115e-17  5.551115e-17
# [2,] 2.775558e-17  3.677614e-16 -5.551115e-17
# [3,] 0.000000e+00 -2.775558e-17  5.551115e-17

为了不需要调用 print.listof(),我们可以将 listof class 添加到包含 m 的列表中。然后它会像你想要的那样打印,你也可以不变地访问矩阵值。

mm <- list(proj = m)
class(mm) <- "listof"
mm
# proj :
#              [,1]          [,2]          [,3]
# [1,] 8.326673e-17  5.551115e-17  5.551115e-17
# [2,] 2.775558e-17  3.677614e-16 -5.551115e-17
# [3,] 0.000000e+00 -2.775558e-17  5.551115e-17    
mm$proj[1,]
# [1] 8.326673e-17 5.551115e-17 5.551115e-17

您可以随时更改第一行,只需更改 mm

的名称即可
setNames(mm, "PROJ")
# PROJ :
#              [,1]          [,2]          [,3]
# [1,] 8.326673e-17  5.551115e-17  5.551115e-17
# [2,] 2.775558e-17  3.677614e-16 -5.551115e-17
# [3,] 0.000000e+00 -2.775558e-17  5.551115e-17

最后,这是我们如何将所有这些信息用作一个函数:

f <- function(mat, nm) {
    x <- setNames(list(mat), nm)
    class(x) <- "listof"
    x
}

f(m, "proj")
f(m, "project 1")