在数据框中,找到列的每个元素的下一个较小值的索引
Posted
技术标签:
【中文标题】在数据框中,找到列的每个元素的下一个较小值的索引【英文标题】:In a dataframe, find the index of the next smaller value for each element of a column 【发布时间】:2016-11-07 12:51:26 【问题描述】:问题:
在数据框中,我想创建一个新列作为现有列的下一个较小值的索引。
例如,数据如下所示。已经安排在item, day
。
item day val
1 1 2 3
2 1 4 2
3 1 5 1
4 2 1 1
5 2 3 2
6 2 5 3
首先我想在dplyr
中使用group_by(item)
来选择每个项目的子数据框。
然后对于第 1 行,我向下看这些行并发现第 2 行有一个较小的val
。这就是我想要的,所以我记录了该行对应的day
。第 2 行类似。
请注意,对于第 3 行和第 6 行,它们是相应子数据帧的最后一行,因此没有下一个较小的值。对于第 4 行和第 5 行,当我向下看这些行时,没有更小的 val
。
带有新列的数据框应如下所示。
item day val next.smaller.day
1 1 2 3 4
2 1 4 2 5
3 1 5 1 -1
4 2 1 1 -1
5 2 3 2 -1
6 2 5 3 -1
我想知道是否有任何方法可以使用dplyr
来实现这一点,或者r
中的任何代码,而不是 for 循环。
我发现一个线程询问这个问题的算法。 Given an array, find out the next smaller element for each element 。 这是相关的,并且所提出的算法在时间复杂度方面超过了我,但我仍然发现在我的场景中很难实现。
谢谢!
更新:
这是另一个重新说明我正在寻找的示例。
item day val next.smaller.day
1 1 2 2 5
2 1 4 3 5
3 1 5 1 -1
4 2 1 3 3
5 2 3 1 -1
6 2 5 2 -1
【问题讨论】:
【参考方案1】:您可以按项目对数据进行分组,使用diff
函数计算行之间的差异并检查它是否小于零,然后生成一个逻辑向量,您可以使用该逻辑向量获取下一个日。由于您要在第二天取货,因此您将需要 lead
函数将日期列向前移动,以便它可以匹配您要放置它们的行。
旁注:由于diff
函数创建的向量比原始向量短一个元素,并且您总是将每组的最后一行留出,我们可以将diff
结果填充为FALSE
条件。
library(dplyr);
df %>% group_by(item) %>% mutate(smaller = c(diff(val) < 0, F),
next.smaller.day = ifelse(smaller, lead(day), -1)) %>%
select(-smaller)
# Source: local data frame [6 x 4]
# Groups: item [2]
# item day val next.smaller.day
# <int> <int> <int> <dbl>
# 1 1 2 3 4
# 2 1 4 2 5
# 3 1 5 1 -1
# 4 2 1 1 -1
# 5 2 3 2 -1
# 6 2 5 3 -1
更新:
find.next.smaller <- function(ini = 1, vec)
if(length(vec) == 1) NA
else c(ini + min(which(vec[1] > vec[-1])),
find.next.smaller(ini + 1, vec[-1]))
# the recursive function will go element by element through the vector and find out
# the index of the next smaller value.
df %>% group_by(item) %>% mutate(next.smaller.day = day[find.next.smaller(1, val)],
next.smaller.day = replace(next.smaller.day, is.na(next.smaller.day), -1))
# Source: local data frame [6 x 4]
# Groups: item [2]
#
# item day val next.smaller.day
# <int> <int> <dbl> <dbl>
# 1 1 2 2 5
# 2 1 4 3 5
# 3 1 5 1 -1
# 4 2 1 1 -1
# 5 2 3 2 -1
# 6 2 5 3 -1
【讨论】:
感谢您的回复。您所做的在给定的示例中有效。但是,下一个较小的值可能不在下一行。例如,如果val
是2,3,1
并且day
是2,4,5
,我希望输出是5,5,-1
。你知道如何实现吗?
查看更新。您可以编写一个递归函数来查找下一个较小值的索引,然后使用 dplyr
函数应用它。
非常感谢!我试图编写一个函数来实现我的目标,但我无法弄清楚。您的解决方案效果很好。让我学习一下你的函数递归性质的精神,并在下次尝试应用它。再次感谢!以上是关于在数据框中,找到列的每个元素的下一个较小值的索引的主要内容,如果未能解决你的问题,请参考以下文章