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

R:如何基于data.table中其他非静态列的数量间接创建条件列,r,data.table,R,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

我有以下
数据。表

     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))
对于列“h”之后的四列中的每一列,代码应检查
assoc
中是否存在列名。如果是,并且如果
DT
中相关行的该列中的值不是零,则代码将考虑相应的Rng值(从
assoc
)。检查完所有四列后,代码应返回所考虑的最大范围,并存储在新列“Range”中


我的做法:

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

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


注意:assoc中可能没有出现频率列的原因是原始数据可能有拼写错误。在本例中,120Hz列始终只在120Hz_f列中生成零,因此它永远不会被视为最大范围。没关系。

来回转换为长格式可以实现这一点:

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

来回转换为长格式可以实现这一点:

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

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

有点长,但实现起来很简单

我将DT与以下代码融为一体,并使用将Hz转换为数字的方法,删除“Hz”并将其转换为数字

a <- melt(DT,id.vars=1:4)[value>0][,crit:=as.numeric(gsub("Hz","",variable))]
然后在塔边找到max

## > 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与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

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

有点长,但实现起来很简单

我将DT与以下代码融为一体,并使用将Hz转换为数字的方法,删除“Hz”并将其转换为数字

a <- melt(DT,id.vars=1:4)[value>0][,crit:=as.numeric(gsub("Hz","",variable))]
然后在塔边找到max

## > 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与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

使用您的示例,您能给我们预期的输出吗?例如,不清楚“最大范围”是否对应于最大assoc$Rng或DT中的列。@lmo以_f结尾的列中的最大值。这些值来自assoc。我更新了问题,以便您可以看到想要的结果。我认为您应该在数据格式较长时,在
dcast
之前进行此计算。一般来说,如果您发现要跨这样的列进行计算,您应该使用长表或矩阵而不是宽表;你不需要做交叉表,我认为这通常不是一个好主意,除非这是最后一步。用你的例子,你能给我们预期的输出吗?例如,不清楚“范围的最大值”对应于最大assoc$Rng或DT中的列。@lmo以_f结尾的列中的最大值。这些值来自assoc。我更新了问题,以便您可以看到想要的结果。我认为您应该在数据格式较长时,在
dcast
之前进行此计算。一般来说,如果您发现要跨这样的列进行计算,您应该使用长表或矩阵而不是宽表;你不需要做交叉表,我认为这通常不是一个好主意,除非是最后一步。第二种方法正是我想要的。很有魅力,非常感谢。只是一个小问题。我不熟悉这个结构,但它显然不是一个标准的变量赋值。我们可以做些什么来避免控制台输出?我说的是
assoc[,{DT[,Range:=pmax(Range,(get(Frq)!=0)*Rng)];NULL},by=Frq]
它显示
空数据。1列的表(0行):Frq
@JAR-yep-用
不可见的
包装它第二种方法正是我想要的。很有魅力,非常感谢。只是一个小问题。我不熟悉这个结构,但它显然不是一个标准的变量赋值。我们可以做些什么来避免控制台输出?我说的是
assoc[,{DT[,Range:=pmax(Range,(get(Frq)!=0)*Rng)];NULL},by=Frq]
它显示
空数据。表(0行)共1列:Frq
@JAR yep-将其包装在
不可见的