如何只拟合数据集的线性部分? [英] How to only fit the linear portion of a dataset?

查看:20
本文介绍了如何只拟合数据集的线性部分?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

p=(-50:50)^2
y=c(p, 2500+10*(1:99), p+1000)
plot(seq_along(y), y+100*rnorm(length(y)))
假设我有一个类似上面的数据集,其中只有一部分数据是线性的。像R中的lm()这样的普通线性回归无法智能地找出适合线性拟合的区域(在本例中为100到200)。

如何找出数据的哪一部分是线性的,并仅在此数据集中执行拟合?欢迎使用R和Python两种解决方案。

注意,上面显示的日期只是一个示例,该方法对于包含线性部分的任意数据集应该是健壮的。当有多个线性部分时,它也应该显示这些多个线性部分。如果没有线性部分,则应该显示没有找到线性部分。

编辑:一般情况下,统计方法可能不适合有力地解决此问题。我添加了计算机视觉和机器学习标签。也许这些领域的方法中的方法总体上更适合于稳健地解决这个问题?

推荐答案

我不知道一个很好的内置方法来实现这一点,正如Ben Bolker和其他人指出的那样,这不是一个能够以健壮、概括的方式回答的简单问题。也就是说,我用暴力的方法解决了这个具体问题,取得了一些成功。因为我更熟悉tidyverse语法,所以我使用了它,但我确信这可以在base R中以类似的方式完成。

首先,我根据开始的x和序列的长度创建了一个要浏览的范围网格。根据要执行的计算量调整粒度。为了快速实现,我使用了每5个xlength个,它们是5的倍数。这样就得到了1,830个x区域,我将关联的y追加到这些区域中。然后,我将xy嵌套到一个新列data中。

# From OP
p=(-50:50)^2
y=c(p, 2500+10*(1:99), p+1000)


library(tidyverse); library(broom)

df1 <- data.frame(x = seq_along(y), y = y+100*rnorm(length(y)))

df1_ranges = crossing(start  = seq.int(1, max(df1$x), by = 5), 
                      length = seq.int(5, 300, by = 5)) %>%
    mutate(end = start + length - 1) %>%
    filter(end <= max(df1$x)) %>%     # only keep ranges within the data
    uncount(length, .id = "x") %>%    # for each x, put in "length" many rows
    mutate(x = start + x - 1) %>%     # update x to run from "start" to "end"
    left_join(df1) %>%
    nest(data = c(x, y))
不能对这些范围中的每一个运行lm回归。这在我的计算机上大约需要9秒。您可以通过查看较少的不同范围或更巧妙地使用搜索空间来加快速度。

df1_regressions <- df1_ranges %>%
    mutate(fit = map(data, ~lm(y~x, data = .x)),   # run lm's
           glance = map(fit, glance),              # summary of fit
           tidied = map(fit, tidy))                # extract coefficients
跳到追逐,对于本例,具有最佳线性拟合的区域具有最低的回归项标准误差。果然,这确定了正确的位置,大约在100到200之间。

df1_tidied <- df1_regressions %>%
    select(start:end, tidied) %>%
    unnest(tidied) %>%
    filter(term == "x")

df1_tidied %>%
    ggplot(aes(x =  start, y = end-start, fill = 1/std.error)) +
    geom_tile() +
    geom_text(data = . %>% filter(std.error == min(std.error)) %>% 
              mutate(text = glue::glue("({start}, {end-start})")), 
          aes(label = text), color = "white", vjust = -0.5) +
    scale_fill_viridis_c(direction = -1, option = "C")

哇!现在,我们可以按照您最初的要求进行操作,只查看该部分的拟合回归。

df1_tidied %>% 
    slice_min(std.error) %>%
    select(start,end) %>%
    left_join(df1_ranges) %>%
    mutate(fit = map(data, ~lm(y~x, data = .x)),
           augment = map(fit, augment)) %>% 
    unnest(augment) -> df1_fitted

ggplot(df1, aes(x,y)) + 
    geom_point() +
    geom_line(data = df1_fitted, aes(y = .fitted), color = "red", size = 2)

这篇关于如何只拟合数据集的线性部分?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆