4

我有一个大数据框 (df),二项式值范围为 1 到 2。数据中也包含 NA。作为一个实际示例,我将创建一个包含用户数据子集的短向量:

df <- c(NA,NA,2,1,1,1,2,1,2,2,1,1,1,NA,2,2,1,2,1,1,1,2)

作为结果,我基本上想要的是一个函数,它搜索2数组的第一个和第二个 s 并将此间隔内的所有内容转换为 2。但是,如果第二个和第一个 2 的位置之间的差异 > 3 然后值保持原样并且不执行任何更改。

除了上述之外,该函数还必须对 的每个值进行循环df。例如,再次考虑以下情况:

df <- c(NA,NA,2,1,1,1,2,1,2,2,1,1,1,NA,2,2,1,2,1,1,1,2)

该函数应具有以下结果:

df_outcome <- c(NA,NA,2,1,1,1,2,2,2,2,1,1,1,NA,2,2,2,2,1,1,1,2)

请注意,df_outcome第一个和第二个 2 之间的值没有合并,因为它们的位置差异大于 3。另一方面,其他非 2 值也相应更改。

我试图做的(但它不能正常工作):

rollapply在包中的帮助下zoo,我尝试创建一个函数来查找数组的第一个和第二个 2 并执行上述修改。

func <- function (q) {
  for (i in (which(q %in% 2)[1]):(which(q %in% 2)[2])) {
    q[i]<-2
  }
  return(q)
}

然后我使用嵌套它,rollapply这样我就可以为每个循环指定一个特定的宽度以及其他参数,例如结果索引的位置(左)。

df_outcome<-rollapply(df, width = 3, FUN = func, fill = NA, partial = TRUE, align = "left")

问题是用户生成的函数在应用于向量时有效。但是,当作为参数嵌套在rollapply函数中时,它会返回错误:

(which(q %in% 2)[1]):(which(q %in% 2)[2]) 中的错误:NA/NaN 参数调用自:FUN(data[replace(posns, !ix, 0) ], ...)

我想我在使用rollapply数据或数据格式方面存在一些错误,但我不明白可能是什么问题。我考虑使用rollapply,因为我的数据很长,并且是为不同的用户生成的。因此,我需要一个函数,该函数还可以根据其他变量(例如in或inUser_ID的参数)拆分数据。.variablesddplybydata.table

期待您的支持。

4

3 回答 3

6

一个解决方案rle

rldf <- rle(df)
rllag <- c(tail(rldf$values,-1), NA)
rllead <- c(NA, head(rldf$values,-1))

rldf$values[which(rldf$values == 1 & rllag == 2 & rllead == 2 & rldf$lengths < 3)] <- 2

df_out <- inverse.rle(rldf)

这使:

> df_out
 [1] NA NA  2  1  1  1  2  2  2  2  1  1  1 NA  2  2  2  2  1  1  1  2

> identical(df_outcome,df_out)
[1] TRUE
于 2016-10-27T12:49:25.383 回答
5

您可以尝试获取2in的索引df。然后得到这些位置之间的差异,从而找到要替换的值的索引2

# position of the 2s
pos_df_2 <- which(df==2) 
# which of the difference in positions are less than 3
wh_pos2_inf3 <- which(c(FALSE, diff(pos_df_2)<=3))
# get all indices between positions that are separated by less than 3 elements
ind_to_replace <- unique(unlist(sapply(wh_pos2_inf3, function(x) {pos_df_2[x-1]:pos_df_2[x]}))) 
# replace the elements by 2
df[ind_to_replace] <- 2 
df
#[1] NA NA  2  1  1  1  2  2  2  2  1  1  1 NA  2  2  2  2  1  1  1  2
于 2016-10-27T12:26:35.247 回答
4

使用data.table(但可能有更好的解决方案):

df<-c(NA, NA, 2, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, NA, 2, 2, 1, 2, 1, 1, 1, 2)
dt<-data.table(val=df)
dt[,`:=`(id=rleid(val), p=shift(val,type="lag"), n=shift(val,type="lead"))]
dt[,`:=`(s=.N, f=p[1], e=n[.N]), by=id]
dt[f==2 & e==2 & s<3, val:=2]

详细说明:

以微小的差异创建df测试数据中有两个连续的 1

df<-c(NA, NA, 2, 1, 1, 2, 2, 1, 2, 2, 1, 1, 1, NA, 2, 2, 1, 2, 1, 
  1, 1, 2)
dt<-data.table(val=df)

创建一个rleidval,lag 并领先 val(用于下一步)

dt[,`:=`(id=rleid(val), p=shift(val, type="lag"), n=shift(val, type="lead"))]

然后通过 id(group) 得到组的大小,这个组的上一个和下一个值

dt[,`:=`(s=.N, f=p[1], e=n[.N]), by=id]

现在根据您的要求过滤(前一个下一个是 2,大小小于 3)并将 val 设置为 2

dt[f==2 & e==2 & s<3, val:=2]

最后给出

dt[,val]
[1] NA NA  2  2  2  2  2  2  2  2  1  1  1 NA  2  2  2  2  1  1  1  2

与来源相比:

[1] NA NA  2  1  1  2  2  1  2  2  1  1  1 NA  2  2  1  2  1  1  1  2   

它似乎给出了你所期望的。

于 2016-10-27T10:14:58.903 回答