我有三个数据帧,我想在第一个数据帧中添加一些列,这些列计算第一个数据帧中前两列出现在其他数据帧中的次数,例如。
dataframe - x
a b
1 1
1 2
2 1
2 2
dataframe - y
a b
1 1
1 1
1 2
2 2
2 2
dataframe - z
a b
1 2
2 1
2 1
2 2
所以第一个数据帧将成为
a b y z
1 1 2 0
1 2 1 1
2 1 0 2
2 2 2 1
我有办法做到这一点,例如我正在做
x$y<- sapply(1:nrow(x), function(i){
sum(y$a == x$a[i] & y$b == x$b[i])
}
x$z<- sapply(1:nrow(x), function(i){
sum(z$a == x$a[i] & z$b == x$b[i])
}
但我的数据框架非常大,我的方式需要一段时间才能完成,所以我想知道最快的方法。
请询问是否有任何不清楚的地方。
提前致谢
答案 0 :(得分:2)
这可能会更快:
# Recreate your data
x <- data.frame(a=c(1,1,2,2), b=c(1,2,1,2))
y <- data.frame(a=c(1,1,1,2,2), b=c(1,1,2,2,2))
z <- data.frame(a=c(1,2,2,2), b=c(2,1,1,2))
# Use paste to combine the two columns in each data.frame
X <- do.call(paste, c(x, sep="-"))
Y <- do.call(paste, c(y, sep="-"))
Z <- do.call(paste, c(z, sep="-"))
# Count number of times each element of X appears in Y and Z
x$y <- sapply(X, function(string) sum(string==Y))
x$z <- sapply(X, function(string) sum(string==Z))
x
# a b y z
# 1 1 1 2 0
# 2 1 2 1 1
# 3 2 1 0 2
# 4 2 2 2 1
答案 1 :(得分:2)
为了避免双循环,我会使用函数匹配,它被优化用于查找另一个列表中的元素。为了计算多少元素,我建议先将变量制成表格,然后再与表格匹配。
我的猜测是它会显着降低时间复杂度,因为你提出的方法是二次方(一个循环遍历x行,每个内循环遍历y行),而函数匹配和表基于排序(我认为)相当于n * log(n)。
我们首先将数据框转换为带有粘贴的矢量,取自Josh的答案:
# Recreate your data
x <- data.frame(a=c(1,1,2,2), b=c(1,2,1,2))
y <- data.frame(a=c(1,1,1,2,2), b=c(1,1,2,2,2))
z <- data.frame(a=c(1,2,2,2), b=c(2,1,1,2))
# Use paste to combine the two columns
X <- do.call(paste, c(x, sep="_"))
Y <- do.call(paste, c(y, sep="_"))
Z <- do.call(paste, c(z, sep="_"))
然后我们制表并匹配表格。
x$y <- table(Y)[match(X, names(table(Y)))]
x$y[is.na(x$y)] <- 0
x$z <- table(Z)[match(X, names(table(Z)))]
x$z[is.na(x$z)] <- 0
x
a b y z
1 1 1 2 0
2 1 2 1 1
3 2 1 0 2
4 2 2 2 1
如果要避免两次制表,可以将表(Y)放在中间变量中。
答案 2 :(得分:2)
你说你的数据帧非常大,所以这是data.table
方式:
> require(data.table)
> x <- data.table(a=c(1,1,2,2), b=c(1,2,1,2))
> y <- data.table(a=c(1,1,1,2,2), b=c(1,1,2,2,2))
> z <- data.table(a=c(1,2,2,2), b=c(2,1,1,2))
>
> setkey(x,a,b) # sort and mark as sorted by a,b
> setkey(y,a,b) # same for y
> setkey(z,a,b) # same for z
> x[,y:=y[x,.N][[3]]]
# join to y from x, using the key.
# .N = number of matching rows
# := means assign by reference back to column y in x, no copy at all
# [[3]] can be understood by running `y[x,.N]` on its own
a b y
[1,] 1 1 2
[2,] 1 2 1
[3,] 2 1 0
[4,] 2 2 2
> x[,z:=z[x,.N][[3]]] # same for z
a b y z
[1,] 1 1 2 0 # bug in v1.8.0 gave z=1 on this row, fixed in v1.8.1
[2,] 1 2 1 1
[3,] 2 1 0 2
[4,] 2 2 2 1
这根本不会复制大对象,甚至一次。它们越大,可能就越重要。