我有两列,只想保留不可交换的行。对于我的输出下方的数据,应该包含 (1 2) 的一种组合。即对于我的查询 (1 2) 与 (2 1) 相同。在 R 中有没有一种简单的方法可以做到这一点。已经尝试过转置。并保留上三角矩阵。但是重新转回数据变得很痛苦。
A B prob
1 2 0.1
1 3 0.2
1 4 0.3
2 1 0.3
2 3 0.1
2 4 0.4
我的最终输出应该是:
A B prob
1 2 0.1
1 3 0.2
1 4 0.3
2 3 0.1
2 4 0.4
我们可以独立sort()
每行然后使用 !
duplicated()
查找要保留的行:
df[!duplicated(t(apply(df[1:2],1L,sort))),];
## A B prob
## 1 1 2 0.1
## 2 1 3 0.2
## 3 1 4 0.3
## 5 2 3 0.1
## 6 2 4 0.4
数据
df <- data.frame(A=c(1L,1L,1L,2L,2L,2L),B=c(2L,3L,4L,1L,3L,4L),prob=c(0.1,0.2,0.3,0.3,0.1,0.4
));
说明
第一步是只提取感兴趣的两列:
df[1:2];
## A B
## 1 1 2
## 2 1 3
## 3 1 4
## 4 2 1
## 5 2 3
## 6 2 4
然后我们用 apply()
独立地对每一行进行排序和 sort()
:
apply(df[1:2],1L,sort);
## [,1] [,2] [,3] [,4] [,5] [,6]
## [1,] 1 1 1 1 2 2
## [2,] 2 3 4 2 3 4
如您所见,apply()
以意外的换位方式返回其结果,因此我们必须使用 t()
修复它为即将到来的 duplicated()
调用做准备:
t(apply(df[1:2],1L,sort));
## [,1] [,2]
## [1,] 1 2
## [2,] 1 3
## [3,] 1 4
## [4,] 1 2
## [5,] 2 3
## [6,] 2 4
现在我们可以使用 duplicated()
来获取一个逻辑向量,指示哪些行与之前的行重复:
duplicated(t(apply(df[1:2],1L,sort)));
## [1] FALSE FALSE FALSE TRUE FALSE FALSE
然后我们用一个否定来反转逻辑向量,只得到那些不与之前任何行重复的行:
!duplicated(t(apply(df[1:2],1L,sort)));
## [1] TRUE TRUE TRUE FALSE TRUE TRUE
最后,我们可以使用生成的逻辑向量来索引 df
中与之前任何行都不重复的那些行:
df[!duplicated(t(apply(df[1:2],1L,sort))),];
## A B prob
## 1 1 2 0.1
## 2 1 3 0.2
## 3 1 4 0.3
## 5 2 3 0.1
## 6 2 4 0.4
因此,将保留每组排序后重复项的第一次出现,其余部分将被删除。
来自@RichardScriven 的极好建议;我们可以用 duplicated()
的 MARGIN
参数替换 t()
调用,这可能会稍微快一些:
df[!duplicated(apply(df[1:2],1L,sort),MARGIN=2L),];
## A B prob
## 1 1 2 0.1
## 2 1 3 0.2
## 3 1 4 0.3
## 5 2 3 0.1
## 6 2 4 0.4