我有一个带有一些非唯一行的矩阵,例如:
x <- read.csv(textConnection(
'0,1,1,0
0,1,1,0
1,0,1,0
0,1,0,1
1,0,0,1'),
header = FALSE)
挑战一种快速的方式(或许称为umat_count
的函数)来获得该矩阵的唯一行的计数,按照它们在x中出现的顺序。理想情况下,结果如下:
y <- umat_count(x)
y
## 2 1 1 1
为了测试这个结果是我想要的,我们可以创建x的唯一版本,然后对其行进行y次采样,然后我们回到x:
ux <- unique(x)
ux[rep(1:nrow(ux), y),]
## V1 V2 V3 V4
## 1 0 1 1 0
## 1.1 0 1 1 0
## 3 1 0 1 0
## 4 0 1 0 1
## 5 1 0 0 1
所以问题是什么是写umat_count
的快捷方式? ATM这是我的笨重代码,但我确信有更好的方法,也许是一个班轮:
umat_count <- function(x) {
xp <- apply(x, 1, paste0, collapse = "") # "pasted" version of constraints
freq <- table(xp) # frequency of occurence of each individual
xu <- unique(x) # save only unique individuals
rns <- as.integer(row.names(xu)) # save the row names of unique values of ind
xpu <- xp[rns]
# xpu <- apply(xu, 1, paste0, collapse = "") # old way of generating ind_pu
o <- order(xpu, decreasing = TRUE) # the order of the output (to rectify table)
y <- freq[o] # frequency with which each individual appears (more efficient way?)
y
}
y <- umat_count(x)
对于上下文,我正在数据准备阶段使用它来努力优化R脚本以进行“空间微观模拟”,如本课程所述:https://www.dropbox.com/s/ffnrl2ofv18rm3n/book-cambridge.pdf?dl=0
非常感谢。
答案 0 :(得分:4)
更新回答:
y <- apply(x, 1, paste, collapse = " ")
y <- rle(sort(as.numeric(factor(y, unique(y), ordered = T))))$lengths
或do.call
方式:
y <- do.call(paste, as.data.frame(x))
y <- rle(sort(as.numeric(factor(y, unique(y), ordered = T))))$lengths
尝试
y <- rle(apply(x, 1, paste, collapse = " "))
# y$lengths is the vector containing the number of times each row appears
# y$values are the rows in the order that y$lengths reports frequency
归功于@JonathanChang,请参阅this page此页面了解他的解决方案。如果行无序,则应在使用rle
之前对其进行排序。
y <- rle(sort(apply(x, 1, paste, collapse = " ")))
答案 1 :(得分:3)
你可以考虑使用“data.table”包,你可以这样使用:
library(data.table)
as.data.table(x, keep.rownames = TRUE)[, list(n = .N, rn = rn[1]), by = names(x)]
# V1 V2 V3 V4 n rn
# 1: 0 1 1 0 2 1
# 2: 1 0 1 0 1 3
# 3: 0 1 0 1 1 4
# 4: 1 0 0 1 1 5
我添加了“rn”列,以确保我们可以在必要时保留行顺序。
如果行被混淆,并且您的目标之一是尝试重新创建原始数据集,我建议创建一个list
行位置,如下所示:
X <- as.data.table(x) ## your new "x" in your answer
X[, rn := sequence(nrow(X))][, list(
.N, rn = list(rn)), by = eval(paste0("V", 1:4))]
# V1 V2 V3 V4 N rn
# 1: 0 1 1 0 3 1,2,6
# 2: 1 0 1 0 1 3
# 3: 0 1 0 1 1 4
# 4: 1 0 0 1 1 5
str(.Last.value)
# Classes ‘data.table’ and 'data.frame': 4 obs. of 6 variables:
# $ V1: int 0 1 0 1
# $ V2: int 1 0 1 0
# $ V3: int 1 1 0 0
# $ V4: int 0 0 1 1
# $ N : int 3 1 1 1
# $ rn:List of 4
# ..$ : int 1 2 6
# ..$ : int 3
# ..$ : int 4
# ..$ : int 5
# - attr(*, ".internal.selfref")=<externalptr>
由于list
中有rn
,您可以稍后使用unlist
和order
恢复原始格式。
答案 2 :(得分:0)
对于记录(抱歉回答我自己的问题),这是另一个使用dplyr的解决方案。无论重复行发生在哪里,都要按正确顺序简洁并获取行。从x开始作为data.frame:
library(dplyr)
rns <-as.integer(row.names(unique(x)))
x$p <- apply(x, 1, paste0, collapse = "")
up <- p[rns]
y <- count(x, p)
o <- order(up, decreasing = TRUE)
y$n[o]
测试rle
解决方案失败的数据集,(感谢Anananda):
x <- read.csv(textConnection(
'0,1,1,0
0,1,1,0
1,0,1,0
0,1,0,1
1,0,0,1
0,1,0,1'),
header = FALSE)
umat_count_dplyr <- function(x){
rns <-as.integer(row.names(unique(x)))
x$p <- apply(x, 1, paste0, collapse = "")
up <- p[rns]
y <- count(x, p)
o <- order(up, decreasing = TRUE)
y$n[o]} # correct order of output
umat_count(x)
V1 V2 V3 V4 p ind_num rns
1 0 1 1 0 0110 2 1
3 1 0 1 0 1010 1 3
4 0 1 0 1 0101 2 4
5 1 0 0 1 1001 1 5
问题:这个解决方案与我原来的umat_count
函数一样长而且慢 - 也许dplyr解决方案对于更大的数据集会相对更快。希望有更好的方法来编写这个整体...
microbenchmark(umat_count(x), umat_count_dplyr(x))
Unit: microseconds
expr min lq mean median uq max neval
umat_count(x) 698.606 714.710 770.613 742.501 770.3165 3061.149 100
umat_count_dplyr(x) 1142.678 1168.565 1249.977 1187.452 1214.5750 3579.286 100