根据数据框中其他列的测试,将NA设置为列

时间:2012-06-06 16:44:33

标签: r plyr na

我有一个包含48列的大型数据框,我想在数据帧的每一行上运行一个函数,通过该函数给出的测试的列设置为NA。此测试涉及从另一个数据框中获取数字。 adply很适合这种情况,但我遇到问题就是给我一些我想要的结果。

让我解释一下:

以下是我想要操作的数据框的示例:

 >df
  pt depth Cell1_avgvel Cell1_avgdir Cell2_avgvel Cell2_avgdir
1  1   0.1           NA           NA           NA           NA
2  2   0.2           NA           NA        1.344        324.0
3  3   0.3           NA           NA        0.445        167.0
4  4   0.4        1.455        354.2        0.322        321.2

以下是从中派生测试的小数据框:

> tcell
  depth  name
1   0.2 Cell1
2   0.4 Cell2
3   0.6 Cell3
4   0.8 Cell4

整个想法是将NA分配给比大数据帧中列出的实际深度更深的单元格的数据点(即在第3行中,深度为0.3但是有两个数据点对应于Cell2,这是0.4米的深度,因此这些都是错误。我想NA这些。)

我想编写一个一次排成一行的函数,并且: 1)抓住仪器深度 2)获取列名列表 3)获得比仪器深度更深的细胞指数 4)获取那些单元格的名称(即Cell1,Cell2,Cell4等) 5)使用正则表达式查找列名列表中具有相应单元格的列(即Cell1_avgdir,Cell1_avgvel等) 6)使用这些索引,将这些列值设置为NA。

这是我到目前为止所拥有的:

depthNA = function(x) {
  depth = x$depth
  nms = names(df)
  ind = as.character(which(depth < tcell$depth))
  c = tcell$name[ind]
  patt = paste(c,collapse="|")
  c_ind = grep(patt,nms)
  x[,c_ind] <- NA
}

adply(df,1,depthNA)

不幸的是,这并没有按照我的想法行事,我现在不知道为什么会这样做。

它给了我这个:

  pt depth Cell1_avgvel Cell1_avgdir Cell2_avgvel Cell2_avgdir V1
1  1   0.1           NA           NA           NA           NA NA
2  2   0.2           NA           NA        1.344        324.0 NA
3  3   0.3           NA           NA        0.445        167.0 NA
4  4   0.4        1.455        354.2        0.322        321.2 NA

当我想要的是:

  pt depth Cell1_avgvel Cell1_avgdir Cell2_avgvel Cell2_avgdir
1  1   0.1           NA           NA           NA           NA
2  2   0.2           NA           NA           NA           NA
3  3   0.3           NA           NA           NA           NA
4  4   0.4        1.455        354.2        0.322        321.2

希望我已经充分解释了我的问题。感谢任何人可以:1)修复我已经开始的事情,或者2)告诉我一个更好的方法去做,我不知道。

-SH

1 个答案:

答案 0 :(得分:1)

以下是一个答案,可以回答您的想法概述但与您的输出不符。请参阅上面关于输出是否正确的评论。答案取决于reshape2,使加入更容易。

首先,我用以下内容阅读您的数据:

df <- read.table(text = "  pt depth Cell1_avgvel Cell1_avgdir Cell2_avgvel Cell2_avgdir
1  1   0.1           NA           NA           NA           NA
2  2   0.2           NA           NA        1.344        324.0
3  3   0.3           NA           NA        0.445        167.0
4  4   0.4        1.455        354.2        0.322        321.2", header = TRUE)

tcell <- read.table(text = " depth  name
1   0.2 Cell1
2   0.4 Cell2
3   0.6 Cell3
4   0.8 Cell4", header = TRUE)

然后解决你的问题:

library(reshape2)

#Melt into long format
df.m <- melt(df, id.vars = 1:2)
#Split the column into two new columns based on _
df.m[, c("Cell", "OtherCol")] <- with(df.m, colsplit(variable, "_", c("Cell", "OtherCol")))
#Merge together with tcell
df.m <- merge(df.m, tcell, by.x = "Cell", by.y = "name")
#Add a new column which sets the offending values to NA
df.m <- transform(df.m, newvalue = ifelse(value > depth.y, NA, value))
#Cast back into wide format
dcast(pt + depth.x ~ variable, value.var = "newvalue", data = df.m)

  pt depth.x Cell1_avgvel Cell1_avgdir Cell2_avgvel Cell2_avgdir
1  1     0.1           NA           NA           NA           NA
2  2     0.2           NA           NA           NA           NA
3  3     0.3           NA           NA           NA           NA
4  4     0.4           NA           NA        0.322           NA