我基本上是在寻找一种在R中对这个Ruby脚本进行变换的方法.
我有一个任意的数字列表(在这种情况下,回归图的主持人的步骤)彼此之间的距离不相等,而且我d想要将这些数字范围内的值舍入到列表中最接近的数字.范围不重叠.
arbitrary.numbers <- c(4,10,15) / 10
numbers <- c(16:1 / 10, 0.39, 1.45)
range <- 0.1
Run Code Online (Sandbox Code Playgroud)
预期产量:
numbers
## 1.6 1.5 1.4 1.3 1.2 1.1 1.0 0.9 0.8 0.7 0.6 0.5 0.4 0.3 0.2 0.1 0.39 1.45
round_to_nearest_neighbour_in_range(numbers,arbitrary.numbers,range)
## 1.5 1.5 1.5 1.3 1.2 1.0 1.0 1.0 0.8 0.7 0.6 0.4 0.4 0.4 0.2 0.1 0.4 1.5
Run Code Online (Sandbox Code Playgroud)
我有一个小助手功能,可能会对我的特定问题做,但它不是很灵活,它包含一个循环.我可以在这里发布,但我认为真正的解决方案看起来完全不同.
> numbers = rep(numbers,length.out = 1000000)
> system.time({ mvg.round(numbers,arbitrary.numbers,range) })[3]
elapsed
0.067
> system.time({ rinker.loop.round(numbers,arbitrary.numbers,range) })[3]
elapsed
0.289
> system.time({ rinker.round(numbers,arbitrary.numbers,range) })[3]
elapsed
1.403
> system.time({ nograpes.round(numbers,arbitrary.numbers,range) })[3]
elapsed
1.971
> system.time({ january.round(numbers,arbitrary.numbers,range) })[3]
elapsed
16.12
> system.time({ shariff.round(numbers,arbitrary.numbers,range) })[3]
elapsed
15.833
> system.time({ mplourde.round(numbers,arbitrary.numbers,range) })[3]
elapsed
9.613
> system.time({ kohske.round(numbers,arbitrary.numbers,range) })[3]
elapsed
26.274
Run Code Online (Sandbox Code Playgroud)
MvG的功能最快,比Tyler Rinker的第二个功能快约5倍.
矢量化解决方案,没有任何apply族函数或循环:
关键是findInterval,找到"空间",arbitrary.numbers其中每个元素都在numbers"之间".所以,findInterval(6,c(2,4,7,8))返回2,因为6是在第二和第三个索引之间c(2,4,7,8).
# arbitrary.numbers is assumed to be sorted.
# find the index of the number just below each number, and just above.
# So for 6 in c(2,4,7,8) we would find 2 and 3.
low<-findInterval(numbers,arbitrary.numbers) # find index of number just below
high<-low+1 # find the corresponding index just above.
# Find the actual absolute difference between the arbitrary number above and below.
# So for 6 in c(2,4,7,8) we would find 2 and 1.
# (The absolute differences to 4 and 7).
low.diff<-numbers-arbitrary.numbers[ifelse(low==0,NA,low)]
high.diff<-arbitrary.numbers[ifelse(high==0,NA,high)]-numbers
# Find the minimum difference.
# In the example we would find that 6 is closest to 7,
# because the difference is 1.
mins<-pmin(low.diff,high.diff,na.rm=T)
# For each number, pick the arbitrary number with the minimum difference.
# So for 6 pick out 7.
pick<-ifelse(!is.na(low.diff) & mins==low.diff,low,high)
# Compare the actual minimum difference to the range.
ifelse(mins<=range+.Machine$double.eps,arbitrary.numbers[pick],numbers)
# [1] 1.5 1.5 1.5 1.3 1.2 1.0 1.0 1.0 0.8 0.7 0.6 0.4 0.4 0.4 0.2 0.1 0.4 1.5
Run Code Online (Sandbox Code Playgroud)
另一个解决方案使用findInterval:
arbitrary.numbers<-sort(arbitrary.numbers) # need them sorted
range <- range*1.000001 # avoid rounding issues
nearest <- findInterval(numbers, arbitrary.numbers - range) # index of nearest
nearest <- c(-Inf, arbitrary.numbers)[nearest + 1] # value of nearest
diff <- numbers - nearest # compute errors
snap <- diff <= range # only snap near numbers
numbers[snap] <- nearest[snap] # snap values to nearest
print(numbers)
Run Code Online (Sandbox Code Playgroud)
在nearest上面的代码是不是真的在数学上最接近的数字。而是最大的任意数字,使nearest[i] - range <= numbers[i]或等价nearest[i] <= numbers[i] + range。因此,我们一口气找到了最大的任意数字,它要么在给定输入数字的捕捉范围内,要么仍然太小。因此,我们只需要检查一种方式snap。不需要绝对值,甚至不需要此帖子的先前版本的平方。
得益于在数据帧上进行间隔搜索以findInterval找到指针所在的位置,因为我在nograpes的答案中识别出它之前就在那里找到了它。
如果与原始问题相反,您有重叠的范围,则可以这样编写:
arbitrary.numbers<-sort(arbitrary.numbers) # need them sorted
range <- range*1.000001 # avoid rounding issues
nearest <- findInterval(numbers, arbitrary.numbers) + 1 # index of interval
hi <- c(arbitrary.numbers, Inf)[nearest] # next larger
nearest <- c(-Inf, arbitrary.numbers)[nearest] # next smaller
takehi <- (hi - numbers) < (numbers - nearest) # larger better than smaller
nearest[takehi] <- hi[takehi] # now nearest is really nearest
snap <- abs(nearest - numbers) <= range # only snap near numbers
numbers[snap] <- nearest[snap] # snap values to nearest
print(numbers)
Run Code Online (Sandbox Code Playgroud)
在此代码中,nearest实际上最终是最接近的数字。这是通过考虑每个间隔的两个端点来实现的。从本质上讲,这ifelse与nograpes的版本非常相似,但是它避免使用and NA,这将减少性能,因为它减少了分支指令的数量。