R:如何在data.table中间接基于非静态数量的其他列间接创建条件列

时间:2016-04-12 19:53:58

标签: r data.table

我有以下data.table

     Name    x    y   h 120Hz 800Hz 1000Hz 1200Hz
1: Tower1 1354  829 245     0     8      7      0
2: Tower2 2654  234 285     7     0      3      0
3: Tower3  822 3040 256     0     4      0      9
4: Tower4  987 2747 250     0     6      5      3
5: Tower5 1953 1739 301     0     0      8      2

您可以使用以下方式创建它:

DT <- data.table(Name = c("Tower1", "Tower2", "Tower3", "Tower4", "Tower5"),
                 x = c(1354,2654,822,987,1953),
                 y = c(829,234,3040,2747,1739),
                 h = c(245,285,256,250,301),
                 `120Hz` = c(0,7,0,0,0),
                 `800Hz` = c(8,0,4,6,0),
                 `1000Hz` = c(7,3,0,5,8),
                 `1200Hz` = c(0,0,9,3,2))

实际上,它来自之前更大的data.table。最后四列是使用data.table从其他dcast自动生成的,因此无法事先知道列h后列的数量或名称。这很重要。

最终目标是创建另一个名为“Range”的列,其每行的值取决于列“h”之后的列中的值,如下所示:

考虑频率和范围之间的以下关联。这些是唯一的建立关联并且是静态的,因此这些信息可以存储为预定义的data.table

assoc <- data.table(Frq = c("800Hz", "1000Hz", "1200Hz"),
                    Rng = c(750,850,950))

对于列“h”之后的四列中的每一列,代码应检查assoc中是否存在列名。如果是,那么如果DT中有关行的该列中的值不为零,那么代码将考虑相应的Rng值(来自assoc)。检查完所有四列后,代码应返回所考虑范围的MAXIMUM,并存储在新列“Range”中。

我的方法:

为每个频率列创建一个辅助列:

DT <- DT[, paste0(colnames(DT)[5:ncol(DT)],'_r') := 0]

然后我可以使用执行上述算法的条件结构。我们以列800Hz_r为例。此列检查800Hz列中的值。如果该值对于所讨论的行不为零,则返回750.最后,列Range仅取前4列的最大值,以_f结尾。我被困在哪里,我找不到有用的命令。我试过的一切都给我一些错误。

最后,应删除辅助_f列。如果有人知道如何在不创建辅助列的情况下做到这一点,那就更好了。

这是预期的结果(在删除辅助列之前):

     Name    x    y   h 120Hz 800Hz 1000Hz 1200Hz 120Hz_f 800Hz_f 1000Hz_f 1200Hz_f Range
1: Tower1 1354  829 245     0     8      7      0       0     750      850        0    850
2: Tower2 2654  234 285     7     0      3      0       0       0      850        0    850
3: Tower3  822 3040 256     0     4      0      9       0     750        0      950    950
4: Tower4  987 2747 250     0     6      5      3       0     750      850      950    950
5: Tower5 1953 1739 301     0     0      8      2       0       0      850      950    950

注意:可能存在未出现在assoc中的频率列的原因是因为原始数据可能存在拼写错误。在该示例中,列120Hz将始终仅在列120Hz_f中生成零,因此它永远不会被考虑用于最大范围。没关系。

2 个答案:

答案 0 :(得分:4)

来回长格式可以使这项工作:

dcast(melt(DT, measure.vars=patterns("Hz$"))[assoc, on = c(variable = 'Frq')
                                                  , Rng := i.Rng * (value != 0)],
      Name + x + y + h ~ variable, max, value.var='Rng')[,
  do.call(function(...) pmax(..., na.rm = T), .SD), .SDcols = `120Hz`:`1200Hz`]
#[1] 850 850 950 950 950

或者,如果循环遍历assoc

,则可以避免创建中间列
DT[, Range := -Inf]

assoc[, {DT[, Range := pmax(Range, (get(Frq) != 0) * Rng)]; NULL}, by = Frq]

DT
#     Name    x    y   h 120Hz 800Hz 1000Hz 1200Hz Range
#1: Tower1 1354  829 245     0     8      7      0   850
#2: Tower2 2654  234 285     7     0      3      0   850
#3: Tower3  822 3040 256     0     4      0      9   950
#4: Tower4  987 2747 250     0     6      5      3   950
#5: Tower5 1953 1739 301     0     0      8      2   950

答案 1 :(得分:0)

这并不完全符合您的意图,但我的座右铭是当算法不适合数据时,然后将数据格式化为算法。

有点长但实施起来很简单。

我使用以下代码融合DT并使用将Hz转换为数字并删除&#34; Hz&#34;并转换为数字。

a <- melt(DT,id.vars=1:4)[value>0][,crit:=as.numeric(gsub("Hz","",variable))]

得到类似的东西:

##> a
##      Name    x    y   h variable value crit
## 1: Tower1 1354  829 245    800Hz     8  800
## 2: Tower1 1354  829 245   1000Hz     7 1000
## 3: Tower2 2654  234 285    120Hz     7  120
## 4: Tower2 2654  234 285   1000Hz     3 1000
## 5: Tower3  822 3040 256    800Hz     4  800
## 6: Tower3  822 3040 256   1200Hz     9 1200
## 7: Tower4  987 2747 250    800Hz     6  800
## 8: Tower4  987 2747 250   1000Hz     5 1000
## 9: Tower4  987 2747 250   1200Hz     3 1200
## 10: Tower5 1953 1739 301   1000Hz     8 1000
## 11: Tower5 1953 1739 301   1200Hz     2 1200

然后通过塔找到最大值。

## > a[,.(crit=max(crit)),by=Name]
##    Name crit
## 1: Tower1 1000
## 2: Tower2 1000
## 3: Tower3 1200
## 4: Tower4 1200
## 5: Tower5 1200

然后用

将其合并
b <- merge(setkey(a,Name,crit),setkey(a[,.(crit=max(crit)),by=Name],Name,crit))

获得类似

的内容
## > b
## Name crit    x    y   h variable value
## 1: Tower1 1000 1354  829 245   1000Hz     7
## 2: Tower2 1000 2654  234 285   1000Hz     3
## 3: Tower3 1200  822 3040 256   1200Hz     9
## 4: Tower4 1200  987 2747 250   1200Hz     3
## 5: Tower5 1200 1953 1739 301   1200Hz     2

然后将b与assoc

合并
## > merge(b,assoc,by.x="variable",by.y="Frq")
## variable   Name crit    x    y   h value Rng
## 1:   1000Hz Tower1 1000 1354  829 245     7 850
## 2:   1000Hz Tower2 1000 2654  234 285     3 850
## 3:   1200Hz Tower3 1200  822 3040 256     9 950
## 4:   1200Hz Tower4 1200  987 2747 250     3 950
## 5:   1200Hz Tower5 1200 1953 1739 301     2 950