我正在处理看起来像这样的原始数据集:
df <- data.frame("ID" = c("Alpha", "Alpha", "Alpha", "Alpha",
"Beta","Beta", "Beta","Beta" ),
"treatment"= LETTERS[seq(from = 1, to = 8)],
"Year" = c(1970, 1970, 1980, 1990, 1970, 1980,
1980,1990),
"Val" = c(0,0,0,1,0,1,0,1),
"Val2" = c(0,2.34,1.3,0,0,2.34,3.2,1.3))
数据有点脏,因为我对每个ID和Year标识符有多个观察结果-例如我在1970年的Alpha中有2个不同的行。在1980年的Beta中也是如此。
问题在于,感兴趣的变量Val
Val2
在重复的行中具有不同的分数(以id / year计)。
我想找到一种简洁的方法来产生以下最终数据帧:
final <- data.frame("ID" = c("Alpha", "Alpha", "Alpha",
"Beta", "Beta","Beta" ),
"treatment"= c("B","C","D","E","G","H"),
"Year" = c(1970, 1980, 1990, 1970,
1980,1990),
"Val" = c(0,0,1,0,0,1),
"Val2" = c(2.34,1.3,0,0,3.2,1.3),
"del_treat" = c("A",NA,NA,NA,"F",NA),
"del_Val"=c(0,NA,NA,NA,1,NA),
"del_Val2"=c(0,NA,NA,NA,2.34,NA))
逻辑如下:
1)我希望每个ID /年只有一个obs
2)我只想保留Val2
类别中具有较高值的观察值。
3)我想将已删除的行值存储到单独的列中,以跟踪我要删除的内容del_treat
,del_Val
和del_Val2
。
进行说明。在df中,对Alpha / 1970有重复的观察。我想将其减少到一行。 Val2取值为0和2.34,在最终数据帧中,仅保留2.34。但是,处理A的值报告在新创建的列del_treat
,del_Val
和del_Val2
中。
我能够根据Val2``setDT(df)[order(-Val2)][,.SD[1,], by = .(ID, Year)]
选择行
值,但我想找到一种简洁的方法来将删除的结果也“存储”到新列中
答案 0 :(得分:2)
这是dplyr
的一个选项。按“ ID”,“年”分组后,创建一个逻辑列(ind),以检查“ Val2”的max
,使用该列创建两个与“ Val”相对应的列,并以“ del”作为前缀那些消除的值以及不存在的“处理”,基于“ ind”和filter
的行ungroup
library(dplyr)
df %>%
group_by(ID, Year) %>%
mutate(ind = Val2 == max(Val2) & !is.na(Val2)) %>%
mutate_at(vars(matches('Val')),
list(del = ~ if(any(!ind)) .[!ind] else NA_real_)) %>%
mutate(del_treat = if(any(!ind)) treatment[!ind] else NA_character_) %>%
filter(ind) %>%
ungroup %>%
select(-ind)
答案 1 :(得分:2)
使用data.table,根据rowid(ID, Year)
降序排列,按Val2
进行广播,除列名外,您都可以到达该列表。 “ _1”列是“ keep”列,而“ _2”列是“ del”列。
library(data.table)
setDT(df)
setorder(df, ID, Year, -Val2)
out <-
dcast(df, ID + Year ~ rowid(ID, Year), value.var = c('treatment', 'Val', 'Val2'))
out
# ID Year treatment_1 treatment_2 Val_1 Val_2 Val2_1 Val2_2
# 1: Alpha 1970 B A 0 0 2.34 0.00
# 2: Alpha 1980 C <NA> 0 NA 1.30 NA
# 3: Alpha 1990 D <NA> 1 NA 0.00 NA
# 4: Beta 1970 E <NA> 0 NA 0.00 NA
# 5: Beta 1980 G F 0 1 3.20 2.34
# 6: Beta 1990 H <NA> 1 NA 1.30 NA
我们可以更改名称以匹配您的名称,唯一的区别是del列的末尾有一个数字。如果每个组的行数大于2,将很有用。
setnames(out, function(x) gsub('(.*)_1', '\\1', x))
setnames(out, function(x) gsub('(.*_\\d+)', 'del_\\1', x))
out
# ID Year treatment del_treatment_2 Val del_Val_2 Val2 del_Val2_2
# 1: Alpha 1970 B A 0 0 2.34 0.00
# 2: Alpha 1980 C <NA> 0 NA 1.30 NA
# 3: Alpha 1990 D <NA> 1 NA 0.00 NA
# 4: Beta 1970 E <NA> 0 NA 0.00 NA
# 5: Beta 1980 G F 0 1 3.20 2.34
# 6: Beta 1990 H <NA> 1 NA 1.30 NA