我有以下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中生成零,因此它永远不会被考虑用于最大范围。没关系。
答案 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