【问题标题】:How to identify a range of data points between a minimum and a maximum in a dataframe in R?如何识别R中数据帧中最小值和最大值之间的数据点范围?
【发布时间】:2020-06-11 12:39:40
【问题描述】:

我的测量变量 V1 遵循循环:上升达到最大值,下降达到最小值。我将“周期”称为 2 个连续最大值之间的数据点范围(周期 1 是最大值 1 - 最小值 1 - 最大值 2,周期 2 是最大值 2 - 最小值 2 - 最大值 3)。每个循环的最小值和最大值是不同的。

我的两个问题是:

  1. 如何识别V1中每个循环对应的数据点范围?

  2. 如何提取 V1 中的所有最小值和所有最大值?

我使用ggplot 来识别我的最小值和最大值,使用stat_peaks()stat_valleys()。我想找到一种不绘制的方法,将其应用于许多数据帧。

library(ggplot2)
library(ggpmisc)
#I plotted my data to visualize the minima (in yellow) and maxima (in blue) with stat_peaks and stat_valleys.
plot <- ggplot(df, aes(x=V0, y=V1))+
  geom_point()+
  stat_peaks(color="yellow", span=61)+
  stat_valleys(color="blue", span=101)
#I used the ggplot_build function to extract the values of the highlighted peaks and valleys.
pb <- ggplot_build(plot)

我想确定 pb 中的 10 个最大值,其中 colour == "yellow"pb 中的 10 个最小值 colour == "blue" 但它不起作用,因为 pb 不是数据框。

dput(df[1:200, c(1,2)]) 
structure(list(V0 = c(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 
0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2, 2.1, 
2.2, 2.3, 2.4, 2.5, 2.6, 2.7, 2.8, 2.9, 3, 3.1, 3.2, 3.3, 3.4, 
3.5, 3.6, 3.7, 3.8, 3.9, 4, 4.1, 4.2, 4.3, 4.4, 4.5, 4.6, 4.7, 
4.8, 4.9, 5, 5.1, 5.2, 5.3, 5.4, 5.5, 5.6, 5.7, 5.8, 5.9, 6, 
6.1, 6.2, 6.3, 6.4, 6.5, 6.6, 6.7, 6.8, 6.9, 7, 7.1, 7.2, 7.3, 
7.4, 7.5, 7.6, 7.7, 7.8, 7.9, 8, 8.1, 8.2, 8.3, 8.4, 8.5, 8.6, 
8.7, 8.8, 8.9, 9, 9.1, 9.2, 9.3, 9.4, 9.5, 9.6, 9.7, 9.8, 9.9, 
10, 10.1, 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 11, 
11.1, 11.2, 11.3, 11.4, 11.5, 11.6, 11.7, 11.8, 11.9, 12, 12.1, 
12.2, 12.3, 12.4, 12.5, 12.6, 12.7, 12.8, 12.9, 13, 13.1, 13.2, 
13.3, 13.4, 13.5, 13.6, 13.7, 13.8, 13.9, 14, 14.1, 14.2, 14.3, 
14.4, 14.5, 14.6, 14.7, 14.8, 14.9, 15, 15.1, 15.2, 15.3, 15.4, 
15.5, 15.6, 15.7, 15.8, 15.9, 16, 16.1, 16.2, 16.3, 16.4, 16.5, 
16.6, 16.7, 16.8, 16.9, 17, 17.1, 17.2, 17.3, 17.4, 17.5, 17.6, 
17.7, 17.8, 17.9, 18, 18.1, 18.2, 18.3, 18.4, 18.5, 18.6, 18.7, 
18.8, 18.9, 19, 19.1, 19.2, 19.3, 19.4, 19.5, 19.6, 19.7, 19.8, 
19.9, 20), V1 = c(32.56, 31.97, 29.08, 27.34, 25.34, 22.58, 
20.93, 17.93, 14.65, 12.2, 9.88, 7, 5.52, 3.96, 3.26, 2.76, 3.23, 
3.38, 3.5, 3.67, 4.24, 7.1, 9.94, 14.58, 17.57, 21.64, 23.83, 
27.28, 29.48, 33.13, 34.37, 36.74, 37.13, 36.52, 35.87, 36, 35.49, 
33.81, 32.89, 30.47, 29.87, 27.84, 25.83, 23.31, 21.39, 18.63, 
16.42, 12.9, 10.6, 7.43, 5.95, 4.52, 3.76, 2.61, 2.94, 3.42, 
2.89, 3.38, 3.64, 4.2, 5.74, 9.48, 12.71, 17.46, 19.76, 23.93, 
27.46, 31.99, 34.07, 40.37, 46.48, 42.89, 48.33, 56.99, 47.16, 
43.53, 39.86, 37.48, 30.36, 26.01, 23.03, 20.57, 15.92, 13.87, 
11.61, 8.58, 6.52, 4.79, 3.88, 2.9, 2.94, 3.22, 3.45, 3.66, 3.89, 
6.01, 8.37, 12.83, 15.06, 18.68, 21.2, 24.12, 26.97, 28.48, 26.69, 
37.06, 40.15, 39.36, 35.73, 35.61, 35.83, 35.14, 31.55, 30.05, 
25.34, 24.24, 23.4, 21.09, 18.32, 16.04, 13.18, 10.07, 8.23, 
5.78, 4.71, 3.44, 3.48, 3.71, 3.72, 3.9, 4.56, 6.93, 9.3, 14.04, 
14.66, 16.25, 18.43, 20.76, 21.86, 23.87, 26.63, 24.85, 29.98, 
26.67, 26.99, 27.36, 25.08, 25.24, 26.48, 24.1, 22.66, 22.28, 
23.29, 21.87, 21.02, 19.53, 22.75, 22.04, 20.64, 19.05, 19.4, 
21, 18.93, 25.38, 23.59, 21.48, 21.9, 23.75, 23.38, 25.06, 25.2, 
26.38, 25.22, 28.62, 27.38, 34.16, 35.94, 34.03, 28.95, 24.33, 
24.76, 25.56, 24.96, 21.99, 23.53, 23.76, 24.5, 22.39, 23.01, 
23.42, 24, 22.65, 21.44, 22.15, 21.72, 18.46, 17.65, 15.34, 16.11, 
14.93)), row.names = c(NA, 200L), class = "data.frame")

【问题讨论】:

  • 可能值得添加包stat_peaks()stat_valleys()来自。

标签: r max subset cycle minimum


【解决方案1】:

您可以在数据框中添加一个变量,使用以下行轻松标记最大值和最小值:

df$is_min_max <- c(FALSE, diff(as.numeric(diff(df$V1) > 0)) != 0, FALSE)

我将解释这是如何工作的:


您可以通过以下方式找出数据中连续点之间的差异

diff(df$V1)

这样您就可以通过执行操作来查看数据的上升或下降位置

as.numeric(diff(df$V1) > 0)

这将在向上渐变的两点之间给出 1,在向下渐变的两点之间给出 0。所以如果你这样做了

diff(as.numeric(diff(df$V1) > 0))

您将在方向改变的点获得 +1 或 -1。

如果你这样做:

diff(as.numeric(diff(df$V1) > 0)) != 0

您将获得局部最大值和最小值点的逻辑向量。请注意,起点和终点已被删除,因为我们有双重差异。因此我们需要在两端添加一个 FALSE:

c(FALSE, diff(as.numeric(diff(df$V1) > 0)) != 0, FALSE)

所以我们可以将其添加到您的数据框中

df$is_min_max <- c(FALSE, diff(as.numeric(diff(df$V1) > 0)) != 0, FALSE)

您的示例中没有包含实际数据,因此我将在此处使用简单的正弦波显示示例:

df <- data.frame(x = seq(1, 20, 0.1), V1 = sin(seq(1, 20, 0.1)))
plot(df$x, df$V1)

现在我们可以找到我们的局部最大值和最小值......

df$is_min_max <- c(FALSE, diff(as.numeric(diff(df$V1) > 0)) != 0, FALSE)

并绘制它们:

points(df$x[df$is_min_max], df$V1[df$is_min_max], col = "red", cex = 3 )

请注意,这将显示每个方向的变化,因此如果您的数据中有局部“摆动”,您也会在那里找到最大值和最小值。删除这些是可能的,但有点复杂。

reprex package (v0.3.0) 于 2020 年 2 月 27 日创建

【讨论】:

  • 谢谢,这很有帮助。我已根据我的需要调整了您的答案。我想将第一个最小值标记为 min1,将第二个最小值标记为 min2 等,最大值相同。这样我就可以定义cycle1,cycle2等。直到现在我还没有那么成功``` df$is_min 0)) == 1, 0) df$min_rank 0)) == -1, 0) df$max_rank min(df$max_rank), "cycle1",NA) ```
  • @EmilieDeLaSylve 您可以通过 maxmin &lt;- subset(df, df$is_max_min) 将这些点放入另一个数据框中,并像这样标记它们:maxmin$label &lt;- paste0("max_min_", seq(nrow(maxmin)))
  • 谢谢!正如您所指出的,我的数据集中有很多“摆动”,我需要删除它们,因为它们不是真正的最小值/最大值。我正在考虑使用 3 个连续点的平均值而不是单个数据点。你怎么看?
【解决方案2】:

峰谷坐标包含在pb中:

山峰在

pb$data[[2]]
  xintercept yintercept label    x         y PANEL group x.label y.label shape colour size fill alpha stroke
1        7.9  0.9989413   7.9  7.9 0.9989413     1    -1     7.9  0.9989    19 yellow  1.5   NA    NA    0.5
2       14.1  0.9993094  14.1 14.1 0.9993094     1    -1    14.1  0.9993    19 yellow  1.5   NA    NA    0.5

山谷在

pb$data[[3]]
  xintercept yintercept label  x          y PANEL group x.label y.label shape colour size fill alpha stroke
1         11 -0.9999902    11 11 -0.9999902     1    -1      11      -1    19   blue  1.5   NA    NA    0.5

请注意,列表元素的顺序可能会根据 ggplot 函数调用的顺序(layers)发生变化。

另请注意,OP 提供的样本数据相对于调用stat_peaks(color="yellow", span=61)stat_valleys(color="blue", span=101) 中给出的跨度太小,分别。

因此,我使用了来自Allan's answer的样本数据:

df <- data.frame(V0 = seq(1, 20, 0.1), V1 = sin(seq(1, 20, 0.1)))

使用 OP 的代码突出显示两个峰和一个谷:

library(ggplot2)
library(ggpmisc)
plot <- ggplot(df, aes(x=V0, y=V1))+
  geom_point()+
  stat_peaks(color="yellow", span=61)+
  stat_valleys(color="blue", span=101)
plot

【讨论】:

    猜你喜欢
    • 2012-05-12
    • 1970-01-01
    • 2013-06-05
    • 2021-11-27
    • 1970-01-01
    • 2021-08-18
    • 1970-01-01
    • 2013-07-02
    • 2020-02-05
    相关资源
    最近更新 更多