我有2个数据帧,比如A和B,大小相等(行和列)。我想输出一个相同大小的数据帧,比如C,所有的值都是0或1。
C[i,j] = 0, if A[i,j] != B[i,j]
C[i,j] = 1, if A[i,j] == B[i,j]
我不想使用循环或ifelse语句,因为我已成功完成,但需要很长时间。如果有任何其他直接的方法来做同样的事情,那将非常有帮助。感谢
答案 0 :(得分:6)
只需比较两个data.frame
以获得具有相同大小的matrix
,并在单元格中指示比较结果的逻辑:
A <- mtcars
B <- mtcars
A == B
结果(仅显示第一行):
mpg cyl disp hp drat wt qsec vs am gear carb
Mazda RX4 TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
Mazda RX4 Wag TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
Datsun 710 TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
Hornet 4 Drive TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
要从比较中获得data.frame
:
C <- as.data.frame(A == B)
您可以使用R中的TRUE
== 1和FALSE
== 0(OP要求)将结果明确强制转换为整数的事实:
as.data.frame(lapply(as.data.frame(A == B), as.integer))
乘以1(在另一个答案中提出)更漂亮,可能更有效(避免:
as.data.frame(1 * (A == B))
编辑++ [添加基准;为了一致性而改进了基准测试]:
基于data.frame
和10 Mio的不同答案之间的基准。行(约260 MB)......
library(microbenchmark) # install.packages("microbenchmark")
library(data.table)
A <- data.frame(col1 = 1:1E7,
col2 = rep(c("a string", "another string"), 1E7/2),
col3 = 1:1E7,
col4 = 1:1E7,
col5 = rep(LETTERS[1:10],1E6),
stringsAsFactors = FALSE)
B <- A
B[1,1]=100 # change one cell to create a copy of the data.frame
microbenchmark(DF.equals = as.data.frame(A == B),
DF.mult = as.data.frame(1 * (A == B)),
DF.map = as.data.frame(Map(`==`, A, B)),
matrix.equals = A == B,
matrix.mult = 1 * (A == B),
matrix.map = do.call(cbind, Map(`==`, A, B)), # causes a warning: duplicated levels in factors are deprecated
list.map = Map(`==`, A, B), # fast cause it does not construct a matrix but only vectors
times = 100)
显示Map()
函数作为明显的赢家(在我的系统上)比其他变体快两到四倍,结果为matrix
比data.frame
快得多:
Unit: milliseconds
expr min lq mean median uq max neval cld
DF.equals 627.2541 630.7565 654.0266 635.1831 678.8903 686.0753 100 e
DF.mult 743.8531 751.7933 781.1876 796.2282 799.1881 848.2455 100 f
DF.map 169.6967 170.5842 176.5944 171.5072 173.5665 223.3354 100 a
matrix.equals 294.2570 297.5330 311.8095 299.8093 345.0827 351.9193 100 c
matrix.mult 402.6166 406.5279 422.9322 408.3012 453.4484 602.2139 100 d
matrix.map 206.2596 208.4230 217.8891 209.8968 211.4139 266.1867 100 b
list.map 169.1922 170.5403 175.7539 171.4602 173.3891 224.7062 100 a
<强>顺便说一句:强>
我真正喜欢的是你现在如何做一些统计数据,例如: G。计算每列不匹配的数量(如果使用rowSums
,则计算行数):
colSums(C != TRUE)
或
colSums(A != B)
获得可用于自动检查前提条件的结果(例如,不允许不匹配):
mpg cyl disp hp drat wt qsec vs am gear carb
0 0 0 0 0 0 0 0 0 0 0
答案 1 :(得分:5)
尝试:
C <- data.frame(1 * (A == B))
1*
用于根据需要将TRUE
/ FALSE
设置为0/1。
答案 2 :(得分:4)
我们可以使用Map
来比较两个data.frame'A'和'B'
Map(`==`, A, B)
优点是我们在工作区中获得list
个逻辑vector
而不是matrix
。如果数据集非常大,那么可能是内存限制以获得矩阵输出
答案 3 :(得分:1)
此示例生成一个T / F矩阵,可以在R
中有效地将其视为0/1x = matrix(1:9, nrow = 3)
y = matrix(9:1, nrow = 3)
x == y
由于答案中还有其他一些建议,我认为我测试哪个是最快的,因为这是问题的要求。
此处equals指的是A == B
解决方案,map_xy是Map
解决方案。
microbenchmark(equals(x,y), map_xy(x,y), times = 1000)
Unit: nanoseconds
expr min lq mean median uq max neval
equals(x, y) 360 399 468.491 459.0 508 3473 1000
map_xy(x, y) 10909 12114 13506.830 13132.5 14158 77743 1000
看起来equals是一个更快的选择 - 但是Map
答案表明它可能会在更大的数据集中表现更好。所以我再次使用合理大小的数据进行测试:
x_big = matrix(1:900000, nrow = 3)
> y_big = matrix(900000:1, nrow = 3)
> microbenchmark(equals(x_big,y_big), map_xy(x_big,y_big), times = 100)
Unit: milliseconds
expr min lq mean median uq
equals(x_big, y_big) 1.579069 2.118332 2.515257 2.225747 2.375377
map_xy(x_big, y_big) 846.172497 1040.383027 1165.354138 1147.239396 1321.166762
max neval
21.48414 100
1489.81884 100
这表明等于仍然是更快的选择。
修改强>
对于评论,这里是每个功能的代码。我稍微编辑了这些以将输出转换为data.frame(虽然我个人认为这一步是不必要的)
equals = function(x,y){
as.data.frame(x == y)
}
map_xy = function(x,y){
Map('==', x, y) %>%
unlist(.) %>%
matrix(., nrow = 3) %>%
as.data.frame(.)
}
这会改变基准测试结果,但不会改变结果:
对于小矩阵:
Unit: microseconds
expr min lq mean median uq max neval
equals(x, y) 18.090 20.3205 24.31075 22.0205 23.7285 781.048 1000
map_xy(x, y) 172.699 186.0775 209.39585 193.3645 204.0220 2646.419 1000
对于大型矩阵:
Unit: milliseconds
expr min lq mean median uq max
equals(x_big, y_big) 533.3274 646.0605 744.063 705.4923 871.3479 1067.411
map_xy(x_big, y_big) 1637.2882 1820.8714 1938.458 1921.2563 2041.0533 2564.669
neval
100
100
如果你想要我最初使用的功能 - 只需取出转换成data.frame的代码即可。