使用data.table在两列之间交换值

15

我一直在煞费苦心地翻译这个问题,以求用data.table找到解决方案。(为了简单起见,我将使用相同的数据集)
V2 == "b"时,我想要交换V1 <-> V3之间的列。

dt <- data.table(V1=c(1,2,4), V2=c("a","a","b"), V3=c(2,3,1))
#V1 V2 V3
#1:  1  a  2
#2:  2  a  3
#3:  4  b  1
下面的代码是对于data.frame的解决方案,但由于我使用了data.table而没有意识到这一点,导致我感到非常沮丧,现在我决心为data.table寻找一个解决方案。
dt <- data.table(V1=c(1,2,4), V2=c("a","a","b"), V3=c(2,3,1))
df <- as.data.frame(dt)
df[df$V2 == "b", c("V1", "V3")] <- df[df$V2 == "b", c("V3", "V1")] 
#  V1 V2 V3
#1  1  a  2
#2  2  a  3
#3  1  b  4

我已经尝试编写了一个lapply函数来遍历我的目标交换列表,试图将问题缩小到仅替换一个值,尝试以不同的方式调用列名,但都没有成功。
这是我最接近成功的尝试:

> dt[dt$V2 == "b", c("V1", "V3")] <- dt[dt$V2 == "b", c(V3, V1)]
#Warning messages:
#1: In `[<-.data.table`(`*tmp*`, dt$V2 == "b", c("V1", "V3"), value = c(1,  :
#  Supplied 2 items to be assigned to 1 items of column 'V1' (1 unused)
#2: In `[<-.data.table`(`*tmp*`, dt$V2 == "b", c("V1", "V3"), value = c(1,  :
#  Supplied 2 items to be assigned to 1 items of column 'V3' (1 unused)

我们如何获得data.table解决方案?

2个回答

17

我们可以尝试

dt[V2=="b", c("V3", "V1") := .(V1, V3)]

我猜使用.SD比传递list(V1, V3)要快? - BenBarnes
1
@BenBarnes 我没有测试过它是否会更快,看起来 list(V1, V3) 也可以。 - akrun
@eddi,你对.SDcols有什么意见吗?我认为如果你有一个预定义列的向量,它是更强大的解决方案。 - David Arenburg
1
@DavidArenburg 这是一个奇怪的问题 :) 我对 .SDcols 没有任何意见,当它被适当地使用时。在这种情况下,它只是增加了额外的符号来表示类型,并使解决方案更加不透明。 - eddi

2

仅供娱乐。@akruns的解决方案显然更优。我认为我可以创建一个临时副本,进行条件交换,然后按顺序使用[.data.table操作来删除副本:

 dt[, tv1 := V1][V2=="b", V1 := V3][V2=="b", V3 := tv1][ , tv1 := NULL]

> dt
   V1 V2 V3
1:  1  a  2
2:  2  a  3
3:  1  b  4

5
啊,是的,我交换了“a”值而不是“b”值。看起来改正它几乎没有价值,因为它会非常慢。我只是发帖让人们扔番茄。 - IRTFM
如果你想要有趣的话,至少做一个bitwXor的解决方案;现在这样是不令人感到有趣的。 - eddi
我希望我知道bitwXor是什么。看来我需要做一些搜索。 - IRTFM

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接