移除局部最小值左右两侧的数据
Remove data to the left and right of local minima
我有很多测量结果,我得到的数据看起来像这样:
# Generate example data
x <- 1:100
y <- 100*(1-exp(-0.3*x))
x2 <- 101:200
y2 <- rev(y)
df <- data.frame("x" = c(x, x2),
"y" = c(y, y2))
df$x <- df$x + 50
rm(x, x2, y, y2)
x <- 1:50
y <- 25.91818
x2 <- 251:300
y2 <- 25.91818
df2 <- data.frame("x" = c(x, x2),
"y" = c(y, y2))
rm(x, x2, y, y2)
df <- rbind(df, df2)
rm(df2)
如果我绘制它,我可以看到有最左边和最右边的局部最小值。
library(ggplot2)
p <- ggplot(df, aes(x,y))+
geom_line()+
geom_point(data = data.frame("x" = c(50, 250), "y" = c(25.91818, 25.91818)),
mapping = aes(x, y), colour = "red")+
scale_y_continuous(limits = c(0, 101))
p + annotate("text", label = "minimum 1", x = 50, y = 20) +
annotate("text", label = "minimum 2", x = 250, y = 20)
我想做的是trimminimum 1
左边和minimum 2
右边的那些数据。这不是非常简单,因为这两点之间也可能存在局部最小值,因为真实数据看起来并不理想。我还需要将这个过程应用于许多样本,但我认为这可能是微不足道的,因为我可以使用例如dplyr
和 group_by()
.
我很幸运地使用 ggpmisc
包绘制了局部最小值,但我不确定如何使用它来实际对我的数据进行子集化。为了清楚起见,我在下面包含了执行此操作的代码,并且使用真实数据看起来更好一些:
library(ggpmisc)
p2 <- ggplot(df, aes(x, y))+
geom_line()+
ggpmisc::stat_peaks(col="red", span=3)
p2
我希望这是清楚的,我很乐意澄清任何问题。提前谢谢你。
您可以按照以下步骤执行此操作:
- 根据 x 对数据进行排序 co-ordinates
- 在您排序的数据上,找到 y co-ordinates 的
diff
,对于两端的平坦部分(以及任何平坦部分),它将为 0(或接近 0)之间)
- 从左边开始,找到
diff
不为零(或至少高于最小阈值)的第一个点。将该索引存储为名为 left
的变量
- 从右边开始,找到
diff
不为零(或至少高于最小阈值)的第一个点。将该索引存储为名为 right
的变量
- 对您的数据框进行子集化,使其仅包含行之间的数据
left:right
因此,在您的示例中,我们将:
# Define a minimal threshold above which we are not at the minimum line
minimal_change <- 1e-6
df <- df[order(df$x),] # Step 1
left <- which(diff(df$y) > minimal_change)[1] # Step 2
right <- nrow(df) - which(diff(rev(df$y)) > minimal_change)[1] + 1 # Step 3
df <- df[left:right, ] # Step 4
现在我们可以绘制结果:
ggplot(df, aes(x, y)) +
geom_line()+
geom_point(data = data.frame("x" = c(50, 250), "y" = c(25.91818, 25.91818)),
mapping = aes(x, y), colour = "red") +
scale_y_continuous(limits = c(0, 101)) +
scale_x_continuous(limits = c(0, 300))
我有很多测量结果,我得到的数据看起来像这样:
# Generate example data
x <- 1:100
y <- 100*(1-exp(-0.3*x))
x2 <- 101:200
y2 <- rev(y)
df <- data.frame("x" = c(x, x2),
"y" = c(y, y2))
df$x <- df$x + 50
rm(x, x2, y, y2)
x <- 1:50
y <- 25.91818
x2 <- 251:300
y2 <- 25.91818
df2 <- data.frame("x" = c(x, x2),
"y" = c(y, y2))
rm(x, x2, y, y2)
df <- rbind(df, df2)
rm(df2)
如果我绘制它,我可以看到有最左边和最右边的局部最小值。
library(ggplot2)
p <- ggplot(df, aes(x,y))+
geom_line()+
geom_point(data = data.frame("x" = c(50, 250), "y" = c(25.91818, 25.91818)),
mapping = aes(x, y), colour = "red")+
scale_y_continuous(limits = c(0, 101))
p + annotate("text", label = "minimum 1", x = 50, y = 20) +
annotate("text", label = "minimum 2", x = 250, y = 20)
我想做的是trimminimum 1
左边和minimum 2
右边的那些数据。这不是非常简单,因为这两点之间也可能存在局部最小值,因为真实数据看起来并不理想。我还需要将这个过程应用于许多样本,但我认为这可能是微不足道的,因为我可以使用例如dplyr
和 group_by()
.
我很幸运地使用 ggpmisc
包绘制了局部最小值,但我不确定如何使用它来实际对我的数据进行子集化。为了清楚起见,我在下面包含了执行此操作的代码,并且使用真实数据看起来更好一些:
library(ggpmisc)
p2 <- ggplot(df, aes(x, y))+
geom_line()+
ggpmisc::stat_peaks(col="red", span=3)
p2
我希望这是清楚的,我很乐意澄清任何问题。提前谢谢你。
您可以按照以下步骤执行此操作:
- 根据 x 对数据进行排序 co-ordinates
- 在您排序的数据上,找到 y co-ordinates 的
diff
,对于两端的平坦部分(以及任何平坦部分),它将为 0(或接近 0)之间) - 从左边开始,找到
diff
不为零(或至少高于最小阈值)的第一个点。将该索引存储为名为left
的变量
- 从右边开始,找到
diff
不为零(或至少高于最小阈值)的第一个点。将该索引存储为名为right
的变量
- 对您的数据框进行子集化,使其仅包含行之间的数据
left:right
因此,在您的示例中,我们将:
# Define a minimal threshold above which we are not at the minimum line
minimal_change <- 1e-6
df <- df[order(df$x),] # Step 1
left <- which(diff(df$y) > minimal_change)[1] # Step 2
right <- nrow(df) - which(diff(rev(df$y)) > minimal_change)[1] + 1 # Step 3
df <- df[left:right, ] # Step 4
现在我们可以绘制结果:
ggplot(df, aes(x, y)) +
geom_line()+
geom_point(data = data.frame("x" = c(50, 250), "y" = c(25.91818, 25.91818)),
mapping = aes(x, y), colour = "red") +
scale_y_continuous(limits = c(0, 101)) +
scale_x_continuous(limits = c(0, 300))