行的唯一值
unique values of rows
我经常遇到这样的数据:
#create dummy data frame
data <- as.data.frame(diag(4))
data[data==0] <- NA
data[2,2] <- NA
data
#V1 V2 V3 V4
#1 1 NA NA NA
#2 NA NA NA NA
#3 NA NA 1 NA
#4 NA NA NA 1
行代表参与者,V1 到 V4 列代表参与者所处的条件(例如,V1 下的 1 表示该参与者处于条件 1,V4 下的 1 表示该参与者处于条件 4)。旁注:数据不是对称的,所以有更多的参与者分布在这 4 个条件上。
我想要的是一个包含每个参与者条件的向量:
1 NA 3 4
我写了以下内容,但想知道是否有更有效的方法(即使用更少的代码行)?
#replace entries with condition numbers
cond <- data + matrix(rep(0:3, 4), 4, byrow=TRUE) #add 0 to 1 for condition 1...
#get all unique elements (ignore NAs)
cond <- apply(cond, 1, function(x)unique(x[!is.na(x)]))
#because I ignored NAs just now, cond[2,2] is numeric(0)
#assign NA to all values that are numeric(0)
cond[sapply(cond, function(x) length(x)==0)] <- NA
cond <- unlist(cond)
cond
#[1] 1 NA 3 4
我们可以在'data'中的非NA元素的逻辑矩阵上使用max.col
和ties.method='first'
。为了使只有 NA 元素的行成为 NA,我们将 max.col
索引与逻辑矩阵的 rowSums
相乘,其中 0 个非 NA 行转换为 NA (NA^
).
max.col(!is.na(data), 'first')* NA^!rowSums(!is.na(data))
#[1] 1 NA 3 4
或者另一个选项是 pmax
。我们将列索引与数据相乘,以便非 NA 元素被索引替换。然后,将 pmax
与 na.rm=TRUE
一起使用,并获取每行的最大值。
do.call(pmax, c(col(data)*data, na.rm=TRUE))
#[1] 1 NA 3 4
使用 reshape2
包:
> data$ID <- rownames(data)
> melt(data, 'ID', na.rm=TRUE)
ID variable value
1 1 V1 1
11 3 V3 1
16 4 V4 1
恕我直言,这样做的好处是可以将 ID 变量与治疗因子一起保存;另外,如果您有响应测量,它也会出现在值列中。
编辑:
如果你想在任何条件下都包含主题,你可以显式地重建那个指示变量:
data$VNA <- ifelse(apply(is.na(data), 1, all), 1, NA)
不如其他解决方案聪明和高效,但可能更具可读性?
apply(data,
MARGIN = 1,
FUN = function(x) {
if(all(is.na(x))) return(NA)
return(which(!is.na(x)))
}
)
# [1] 1 NA 3 4
我经常遇到这样的数据:
#create dummy data frame
data <- as.data.frame(diag(4))
data[data==0] <- NA
data[2,2] <- NA
data
#V1 V2 V3 V4
#1 1 NA NA NA
#2 NA NA NA NA
#3 NA NA 1 NA
#4 NA NA NA 1
行代表参与者,V1 到 V4 列代表参与者所处的条件(例如,V1 下的 1 表示该参与者处于条件 1,V4 下的 1 表示该参与者处于条件 4)。旁注:数据不是对称的,所以有更多的参与者分布在这 4 个条件上。
我想要的是一个包含每个参与者条件的向量:
1 NA 3 4
我写了以下内容,但想知道是否有更有效的方法(即使用更少的代码行)?
#replace entries with condition numbers
cond <- data + matrix(rep(0:3, 4), 4, byrow=TRUE) #add 0 to 1 for condition 1...
#get all unique elements (ignore NAs)
cond <- apply(cond, 1, function(x)unique(x[!is.na(x)]))
#because I ignored NAs just now, cond[2,2] is numeric(0)
#assign NA to all values that are numeric(0)
cond[sapply(cond, function(x) length(x)==0)] <- NA
cond <- unlist(cond)
cond
#[1] 1 NA 3 4
我们可以在'data'中的非NA元素的逻辑矩阵上使用max.col
和ties.method='first'
。为了使只有 NA 元素的行成为 NA,我们将 max.col
索引与逻辑矩阵的 rowSums
相乘,其中 0 个非 NA 行转换为 NA (NA^
).
max.col(!is.na(data), 'first')* NA^!rowSums(!is.na(data))
#[1] 1 NA 3 4
或者另一个选项是 pmax
。我们将列索引与数据相乘,以便非 NA 元素被索引替换。然后,将 pmax
与 na.rm=TRUE
一起使用,并获取每行的最大值。
do.call(pmax, c(col(data)*data, na.rm=TRUE))
#[1] 1 NA 3 4
使用 reshape2
包:
> data$ID <- rownames(data)
> melt(data, 'ID', na.rm=TRUE)
ID variable value
1 1 V1 1
11 3 V3 1
16 4 V4 1
恕我直言,这样做的好处是可以将 ID 变量与治疗因子一起保存;另外,如果您有响应测量,它也会出现在值列中。
编辑:
如果你想在任何条件下都包含主题,你可以显式地重建那个指示变量:
data$VNA <- ifelse(apply(is.na(data), 1, all), 1, NA)
不如其他解决方案聪明和高效,但可能更具可读性?
apply(data,
MARGIN = 1,
FUN = function(x) {
if(all(is.na(x))) return(NA)
return(which(!is.na(x)))
}
)
# [1] 1 NA 3 4