基于现有列和相邻列创建新列

3

我的数据框看起来像这样

ID t1 obs1 t2 obs2 t3 obs3
1  0  a    11 d    0  g
2  0  b    13 e    11 i
3  0  c    0  f    0  h

我需要确保每个ID至少有一个大于10的t值(如果没有则删除行)。然后,我想保存大于10的最低t值,同时在新列中保存相应的obs。(我的问题的复杂部分是,大于10的最低t值可能在任何一列中)。某些t对应的相应obs位于下一列中,因此这有所帮助。因此,我的数据框将如下所示:

ID t1 obs1 t2 obs2 t3 obs3 lowesttabove10 correspondingobs
1  0  a    11 d    0  g    11             d
2  0  b    13 e    11 i    11             i
4个回答

4

使用data.table,转换成长格式:

library(data.table)
setDT(DT)
dat = melt(DT, measure.vars = patterns("^t\\d+$", "^obs\\d+$"), value.name = c("t", "obs"))
setorder(dat, ID, variable)

#    ID variable  t obs
# 1:  1        1  0   a
# 2:  1        2 11   d
# 3:  1        3  0   g
# 4:  2        1  0   b
# 5:  2        2 13   e
# 6:  2        3 11   i
# 7:  3        1  0   c
# 8:  3        2  0   f
# 9:  3        3  0   h

查找每个组的最大值并标记要保留的组:

IDDT = dat[order(-t), 
  .(max.variable = first(variable), max.t = first(t), max.obs = first(obs))
, by=ID]
IDDT[, keep := max.t > 10]

#    ID max.variable max.t max.obs  keep
# 1:  2            2    13       e  TRUE
# 2:  1            2    11       d  TRUE
# 3:  3            1     0       c FALSE

使用滚动更新连接查找每个保留组中的最小值:

IDDT[(keep), c("my.variable", "my.t", "my.obs") := {
  m = .(ID = ID, t_thresh = 10)
  dat[m, on=.(ID, t = t_thresh), roll=-Inf, .(x.variable, x.t, x.obs)]
}]

#    ID max.variable max.t max.obs  keep my.variable my.t my.obs
# 1:  2            2    13       e  TRUE           3   11      i
# 2:  1            2    11       d  TRUE           2   11      d
# 3:  3            1     0       c FALSE          NA   NA     NA

我会在这里停下来,用长格式的dat作为主要数据,将ID级别变量放在单独的表格IDDT中。要筛选应该保留的组:dat[IDDT[(keep), .(ID)], on=.(ID)]。有关语法的详细信息,请参见?data.table和加载软件包时提到的其他介绍材料。

如果一定要返回宽格式,请参见?dcast


3
使用基本的R语言:
删除所有t值低于10的行:
df1 <- df1[rowSums(df1[, grepl("^t", colnames(df1))] >10) > 0, ]

确定包含高于10的最小值的组,并检索数值:
df1$group <- apply(df1[grepl("^t", names(df1))], 1, function(x) which(x == min(x[x > 10])))
df1 <- cbind(df1, do.call(rbind, lapply(seq_len(nrow(df1)), 
                                        function(x) setNames(df1[x, paste0(c("t", "obs"), df1$group[x])],
                                                             c("lowesttabove10", "correspondingobs")))))

> df1
  ID t1 obs1 t2 obs2 t3 obs3 group lowesttabove10 correspondingobs
1  1  0    a 11    d  0    g     2             11                d
2  2  0    b 13    e 11    i     3             11                i

2

我的方法可能不够简洁,但它仍然有效。您可以尝试一下。

library(dplyr)
library(reshape)
df1=melt(df,id='ID')

df2=df1%>%group_by(ID)%>%filter(value>10)%>%dplyr::slice(which.min(value))%>%na.omit()

> df2
# A tibble: 2 x 3
# Groups:   ID [2]
     ID variable value
  <int>   <fctr> <chr>
1     1       t2    11
2     2       t3    11


df2$variable=as.character(df2$variable)
C=as.numeric(gsub("[[:alpha:]]", "", df2$variable))
df=df[df$ID%in%df2$ID,]
for (i in 1:length(C)){
DF1=df[i,str_detect(names(df),as.character(C[i]))]
names(DF1)=c('lowesttabove10 ','correspondingobs')
if (i ==1 ){DFF=DF1}else{DFF=rbind(DFF,DF1)}
}
cbind(df,DFF)

  ID t1 obs1 t2 obs2 t3 obs3 lowesttabove10  correspondingobs
1  1  0    a 11    d  0    g              11                d
2  2  0    b 13    e 11    i              11                i

2
reshape 旨在与 plyr 兼容,而 tidyr 则适用于 dplyr。 - Frank
刚刚注意到:你需要将df1$value转换为数字。如果使用字符,你会在筛选器中看到"2" > 10。另外,看起来你的第二步应该/可以是left_join(df2, df) - Frank
@Frank 是的,你说得对,而在我的代码中 '1'>10 返回 FALSE - BENY

2

这个解决方案使用了 dplyrtidyr 两个工具在同一个流程中。其中,dt 是原始数据,而 dt2 则是最终输出结果。

library(dplyr)
library(tidyr)

dt2 <- dt %>%
  gather(t_group, t_value, starts_with("t")) %>%
  gather(obs_group, obs_value, starts_with("obs")) %>%
  filter(gsub("t", "", t_group) == gsub("obs", "", obs_group)) %>%
  filter(t_value >= 10) %>%
  filter(t_value == min(t_value)) %>%
  select(ID, lowesttabove10 = t_value, correspondingobs = obs_value) %>%
  inner_join(dt, by = "ID") %>%
  select(colnames(dt), lowesttabove10, correspondingobs)

df2
  ID t1 obs1 t2 obs2 t3 obs3 lowesttabove10 correspondingobs
1  1  0    a 11    d  0    g             11                d
2  2  0    b 13    e 11    i             11                i

数据:

dt <- read.table(text = "ID t1 obs1 t2 obs2 t3 obs3
1  0  a    11 d    0  g
                 2  0  b    13 e    11 i
                 3  0  c    0  f    0  h",
                 header = TRUE, stringsAsFactors = FALSE)

你知道我为什么会得到这个错误吗?错误:is_dictionaryish(x)不是TRUE。 - rdk
不确定。尝试获取最新的 dplyrtidyverse 包。如果错误仍然发生,您可以使用其他人建议的基本 R 或 data.table 方法。 - www

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