如何使用 dplyr 操作长 table 相关数据,但不将数据转换为宽格式
How to manipulate long-table data for correlations, using dplyr, but without transposing data to wide format
我有一些数据代表患者 (id) 的重复(会话 A 和 B)测量值 (var.x)。我的数据很整洁(即长格式 table,每一列有一个变量,每一行有一个观察值)......像这样:
| id | var.1 | var.2 | session |
--------------------------------
| 1 | 1.1 | 11 | A |
| 1 | 1.9 | 12 | B |
| 2 | 1.2 | 15 | A |
| 2 | 1.4 | 14 | B |
我想对来自会话 A 和 B 的配对(按 ID)数据(例如 var.1)进行相关分析。换句话说,重复测量之间的相关系数是多少..
这不难做到,如果我tranpose/pivot/melt/spread把数据变成像这样的宽格式:
| id | var.1.A | var.2.A | var.1.B | var.2.B |
----------------------------------------------
| 1 | 1.1 | 11 | 1.9 | 12 |
| 2 | 1.2 | 15 | 1.4 | 14 |
...然后我可以简单地 cor(var.1.A, var.1.B)。我意识到 dplyr/tidyr 有 gather/spread/separate/unite 用于此目的的命令,但是这对我来说似乎不整洁且不够优雅,因为我基本上必须复制我的数据。
有没有办法在不重塑数据的情况下使用 dplyr 做到这一点?
我在想一些事情:
data %>%
select(id, var.1, session) %>%
do( cor( filter(session=='A', filter(session=='B'))
...但显然这不起作用,我还需要以某种方式指定数据是配对的(按 id)。
我们可以尝试 dplyr
或 data.table
方法。假设我们想要找到 'var' 列的相关性,我们使用 grep
('nm1') 和自定义函数 (f1
) 创建列的索引。我们在 do
中使用 Map
来获取每个 'var' 列的 cor
。我们使用 'var' 列作为第一个输入,即 'x' 和 'session' 作为 'y'.
nm1 <- grep('^var', names(data))
f1 <- function(x,y) cor(x[y=='A'], x[y=='B'])
library(dplyr)
data %>%
do({data.frame(Map(f1, .[nm1], list(.$session)))})
# var.1 var.2
#1 -1 1
以类似的方式,我们可以使用 data.table
来完成 cor
。
library(data.table)
setDT(data)[, Map(f1, .SD[, nm1, with=FALSE], list(session)) ]
# var.1 var.2
#1: -1 1
如果我们使用 base R
mapply(f1, data[nm1], list(data$session))
# var.1 var.2
# -1 1
如果我们想转换为 wide
格式,我们可以使用 data.table
的开发版本中的 dcast
即 v1.9.5
因为它可以使用多个 value.var
列。
dW <- dcast(setDT(data), id~session, value.var=c('var.1', 'var.2'))[, id:=NULL]
dW
# var.1_A var.1_B var.2_A var.2_B
#1: 1.1 1.9 11 12
#2: 1.2 1.4 15 14
我们可以转换为 matrix
、子集、应用 cor
并获得 diag
值。
m1 <- as.matrix(dW)
diag(cor(m1[,c(TRUE, FALSE)], m1[,c(FALSE, TRUE)]))
#[1] -1 1
数据
data <- structure(list(id = c(1L, 1L, 2L, 2L), var.1 = c(1.1, 1.9, 1.2,
1.4), var.2 = c(11L, 12L, 15L, 14L), session = c("A", "B", "A",
"B")), .Names = c("id", "var.1", "var.2", "session"),
class = "data.frame", row.names = c(NA, -4L))
我想我会添加一个答案,说明如何使用来自 dplyr 的 summarise_each
来做到这一点。
此方法取决于数据集顺序。在这种情况下,我喜欢使用 arrange
来确保数据集处于所需的顺序,但如果您确信事情已经有序,则可以跳过此步骤。
data %>%
arrange(id, session) %>%
summarise_each(funs(cor(.[session == "A"], .[session == "B"])), starts_with("var"))
var.1 var.2
1 -1 1
在 summarise_each
中,.
指的是您要汇总的变量,而在 do
中,它指的是数据集。
你可以简单地写出你想要总结的变量的名称,但我使用函数starts_with
来选择变量。有关这些特殊功能的更多信息,请参阅 select
的帮助页面。
您还需要确保每个 ID 中都有一对。 tidyr 包中的 complete
函数可能会很有用,如果你 运行 遇到 [=20] 中缺少 session
级别之一的情况=].如果是这种情况,您可能需要在 cor
中使用 use
参数。
我有一些数据代表患者 (id) 的重复(会话 A 和 B)测量值 (var.x)。我的数据很整洁(即长格式 table,每一列有一个变量,每一行有一个观察值)......像这样:
| id | var.1 | var.2 | session |
--------------------------------
| 1 | 1.1 | 11 | A |
| 1 | 1.9 | 12 | B |
| 2 | 1.2 | 15 | A |
| 2 | 1.4 | 14 | B |
我想对来自会话 A 和 B 的配对(按 ID)数据(例如 var.1)进行相关分析。换句话说,重复测量之间的相关系数是多少..
这不难做到,如果我tranpose/pivot/melt/spread把数据变成像这样的宽格式:
| id | var.1.A | var.2.A | var.1.B | var.2.B |
----------------------------------------------
| 1 | 1.1 | 11 | 1.9 | 12 |
| 2 | 1.2 | 15 | 1.4 | 14 |
...然后我可以简单地 cor(var.1.A, var.1.B)。我意识到 dplyr/tidyr 有 gather/spread/separate/unite 用于此目的的命令,但是这对我来说似乎不整洁且不够优雅,因为我基本上必须复制我的数据。
有没有办法在不重塑数据的情况下使用 dplyr 做到这一点?
我在想一些事情:
data %>%
select(id, var.1, session) %>%
do( cor( filter(session=='A', filter(session=='B'))
...但显然这不起作用,我还需要以某种方式指定数据是配对的(按 id)。
我们可以尝试 dplyr
或 data.table
方法。假设我们想要找到 'var' 列的相关性,我们使用 grep
('nm1') 和自定义函数 (f1
) 创建列的索引。我们在 do
中使用 Map
来获取每个 'var' 列的 cor
。我们使用 'var' 列作为第一个输入,即 'x' 和 'session' 作为 'y'.
nm1 <- grep('^var', names(data))
f1 <- function(x,y) cor(x[y=='A'], x[y=='B'])
library(dplyr)
data %>%
do({data.frame(Map(f1, .[nm1], list(.$session)))})
# var.1 var.2
#1 -1 1
以类似的方式,我们可以使用 data.table
来完成 cor
。
library(data.table)
setDT(data)[, Map(f1, .SD[, nm1, with=FALSE], list(session)) ]
# var.1 var.2
#1: -1 1
如果我们使用 base R
mapply(f1, data[nm1], list(data$session))
# var.1 var.2
# -1 1
如果我们想转换为 wide
格式,我们可以使用 data.table
的开发版本中的 dcast
即 v1.9.5
因为它可以使用多个 value.var
列。
dW <- dcast(setDT(data), id~session, value.var=c('var.1', 'var.2'))[, id:=NULL]
dW
# var.1_A var.1_B var.2_A var.2_B
#1: 1.1 1.9 11 12
#2: 1.2 1.4 15 14
我们可以转换为 matrix
、子集、应用 cor
并获得 diag
值。
m1 <- as.matrix(dW)
diag(cor(m1[,c(TRUE, FALSE)], m1[,c(FALSE, TRUE)]))
#[1] -1 1
数据
data <- structure(list(id = c(1L, 1L, 2L, 2L), var.1 = c(1.1, 1.9, 1.2,
1.4), var.2 = c(11L, 12L, 15L, 14L), session = c("A", "B", "A",
"B")), .Names = c("id", "var.1", "var.2", "session"),
class = "data.frame", row.names = c(NA, -4L))
我想我会添加一个答案,说明如何使用来自 dplyr 的 summarise_each
来做到这一点。
此方法取决于数据集顺序。在这种情况下,我喜欢使用 arrange
来确保数据集处于所需的顺序,但如果您确信事情已经有序,则可以跳过此步骤。
data %>%
arrange(id, session) %>%
summarise_each(funs(cor(.[session == "A"], .[session == "B"])), starts_with("var"))
var.1 var.2
1 -1 1
在 summarise_each
中,.
指的是您要汇总的变量,而在 do
中,它指的是数据集。
你可以简单地写出你想要总结的变量的名称,但我使用函数starts_with
来选择变量。有关这些特殊功能的更多信息,请参阅 select
的帮助页面。
您还需要确保每个 ID 中都有一对。 tidyr 包中的 complete
函数可能会很有用,如果你 运行 遇到 [=20] 中缺少 session
级别之一的情况=].如果是这种情况,您可能需要在 cor
中使用 use
参数。