我有一个数据集如下。如果取消是" Y"然后美元是负面的,反之亦然。
根据数据,我想在同一个id中删除具有相同的美元但不同符号(当然应该有取消值的不同符号)的对。
DF
rownumber id1 cancel dollar
1 1 Y -50
2 1 N 10
3 1 N 50
4 2 N 14.4
5 2 Y -23.5
6 2 N 23.5
7 3 Y -15.5
8 3 N 15.5
9 4 Y -20.5
因此,这是我想要的输出。
df_desired
rownumber id1 cancel dollar
2 1 N 10
4 2 N 14.4
9 4 Y -20.5
也许,我可以通过使用for循环来做到这一点但是数据太大而无法做到。
有什么简单的方法吗?
答案 0 :(得分:1)
由于iff cancel = Y
有负号,为什么不简单地将绝对值存储在dollar
?然后,您可以获取具有取消+美元的唯一值的行。过滤后,如果需要,可以添加负号。
如果由于某种原因这不是一个选项,如果你有足够的内存来构建数据中的hashset,你仍然可以在O(2)时间内完成它:对于每一行,将dollar
插入到一个hashset中。然后再次迭代并过滤掉hashset包含-dollar
的所有值。
答案 1 :(得分:1)
正如@ Eric.M所说,你可以通过在取dollar
的绝对值后查找重复的行来做到这一点:
df[with(df, ave(rownumber, list(id1, abs(dollar)), FUN=length)==1 ),]
# rownumber id1 cancel dollar
#2 2 1 N 10.0
#4 4 2 N 14.4
#9 9 4 Y -20.5
答案 2 :(得分:1)
你可以这样做:
v <- unlist(aggregate(dollar~id1, df,
function(x) !(duplicated(abs(x)) | duplicated(abs(x), fromLast = T)))$dollar)
df[which(v),]
# rownumber id1 cancel dollar
#2 2 1 N 10.0
#4 4 2 N 14.4
#9 9 4 Y -20.5
在!(duplicated(abs(x)) | duplicated(abs(x), fromLast = T))
使用id1
进行分组后, aggregate
完全符合您的要求。
OR
(感谢@thelatemail指出这一点):
tmp <- interaction(df$id1, abs(df$dollar))
df[!(duplicated(tmp) | duplicated(tmp, fromLast = T)),]
答案 3 :(得分:0)
因为您标记了dplyr
,我们可以像这样使用dplyr
:
df %>% group_by(id1, abs(dollar)) %>% filter(sum(dollar) != 0)
rownumber id1 cancel dollar `abs(dollar)`
<int> <int> <chr> <dbl> <dbl>
1 2 1 N 10.0 10.0
2 4 2 N 14.4 14.4
3 9 4 Y -20.5 20.5
如果旧版分组abs_dollar
列分散注意力%>% ungroup() %>% select(-5)