如何按行运行线性回归并仅在R中具有NA的元素中填充数据?

时间:2018-10-04 14:55:21

标签: r dataframe regression

我有一个数据框,其中包含有关城市人口密度的数据,该数据取决于与市中心的距离(“空间距离剖面”)。

数据框如下所示(示例):

console.log([2,3].includes(1));

“城市”包含城市名称或标识符,而变量“ km1-km4”包含该距离内的人口密度的对数。请注意,示例中的观察值3没有km4的数据;所有城市都没有km5的数据。

我要实现的目标是推断当人口密度遵循指数函数时,城市分布了多少公里。

为此,我想首先对表格的每一行运行线性回归y〜x,其中y是变量km1-kmX,x是距市中心的相应距离(1,2,3,.. )。

set.seed(1)
data <- data.frame(cities = c("city1","city2","city3"),
    km1 = runif(3,6,7),
    km2 = runif(3,5,6),
    km3 = runif(3,4,5),
    km4 = c(3.5,3.2,NA),
    km5 = c(NA,NA,NA)
)

(示例中未定义可变的“距离”,因为我不知道如何将其合并到数据框中。但我希望这个想法能够实现)

因此,对于city1和city2,应使用km1-km4,而对于city3,显然仅应使用km1-km3。

然后将所得系数beta_0和beta_1作为变量存储在相应的行中。

接下来,我要使用系数来计算缺失变量的总体密度的对数,

 lm(km1-kmX ~ distance) 

我知道描述有些模糊;我想尽可能地扩大构思的所有细节。感谢任何帮助。

虽然可能不是必需的,但这是我在以下平台上使用R的平台:
R版本3.4.2(2017-09-28)
平台:x86_64-w64-mingw32 / x64(64位)
在以下环境下运行:Windows> = 8 x64(内部版本9200)

2 个答案:

答案 0 :(得分:1)

假定目标是使用同一行上的非NA值与标题中的数字的线性回归来填充NA值,则首先提取构成{{1}的列名中的数值}。然后定义一个函数,该函数针对x回归行值,并据此预测NA。最后将其应用于每一行。

x

给予:

x <- as.numeric(gsub("\\D", "", names(data)[-1]))  # c(1, 2, 3, 4, 5)
na.lm <- function(r, x) ifelse(is.na(r), predict(lm(r ~ x), list(x = x)), r)
cbind(data[1], t(apply(data[-1], 1, na.lm, x = x)))

答案 1 :(得分:1)

首先,我认为我们需要将您的数据从“宽”格式调整为“高”格式。这将满足Ryan的评论,即您不能对单行进行线性回归-他在技术上是正确的,但我认为他错过了您实际上每行有4-5个观测值,而不是1的要点。(注释已删除。

(第二:从不命名变量data。如果您忘记在新的R会话中创建变量,则依赖于该变量的所有函数都将以奇怪且通常不直观的方式失败,而不是预期的更简单的错误消息Error: object 'data' not found。我将在您的创建代码中使用dat。)

使用tidyverse中的一些软件包对此进行了演示:

library(dplyr)
library(tidyr)
library(purrr)

重塑:首先,您枚举为km1km2等,但是它们是分类变量,而不是数字,我推断您希望将数字存储在其中。因此,您真正拥有的列名称(km1)应该是数据(km = 1)。 (哦,我删除了NA,因为它们无助于提供模型。我们稍后再将它们带回来。)

datlong <- dat %>%
  gather(km, dens, -cities) %>%
  mutate(km = as.numeric(gsub("km", "", km))) %>%
  rename(city = cities) %>%
  filter(complete.cases(.))
datlong
#     city km     dens
# 1  city1  1 6.265509
# 2  city2  1 6.372124
# 3  city3  1 6.572853
# 4  city1  2 5.908208
# 5  city2  2 5.201682
# 6  city3  2 5.898390
# 7  city1  3 4.944675
# 8  city2  3 4.660798
# 9  city3  3 4.629114
# 10 city1  4 3.500000
# 11 city2  4 3.200000

现在的问题是如何对每个城市进行回归。首先,通过将城市的所有数据放在框架的一个“单元”中,让我们“整理”些东西。

datnested <- datlong %>%
  group_by(city) %>%
  nest(.key = "citydat")
datnested
# # A tibble: 3 x 2
#   city  citydat         
#   <fct> <list>          
# 1 city1 <tibble [4 x 2]>
# 2 city2 <tibble [4 x 2]>
# 3 city3 <tibble [3 x 2]>

现在我们可以对每个数据集进行回归:

datmodel <- datnested %>%
  mutate(model = map(citydat, ~ lm(dens ~ km, data = .x)))
datmodel
# # A tibble: 3 x 3
#   city  citydat          model   
#   <fct> <list>           <list>  
# 1 city1 <tibble [4 x 2]> <S3: lm>
# 2 city2 <tibble [4 x 2]> <S3: lm>
# 3 city3 <tibble [3 x 2]> <S3: lm>

是否注意到框架中的嵌入式模型?每个看起来像这样:

datmodel$model[[1]]
# Call:
# lm(formula = dens ~ km, data = .x)
# Coefficients:
# (Intercept)           km  
#       7.470       -0.926  

现在 that 可以在其他地方使用。让我们进行预测:

predkm <- 1:5
datpred <- datmodel %>%
  mutate(pred = map(model, ~ data_frame(km = predkm, preddens = predict(.x, newdata = data.frame(km=predkm)))))
datpred
# # A tibble: 3 x 4
#   city  citydat          model    pred            
#   <fct> <list>           <list>   <list>          
# 1 city1 <tibble [4 x 2]> <S3: lm> <tibble [5 x 2]>
# 2 city2 <tibble [4 x 2]> <S3: lm> <tibble [5 x 2]>
# 3 city3 <tibble [3 x 2]> <S3: lm> <tibble [5 x 2]>

类似地:

datpred$pred[[1]]
# # A tibble: 5 x 2
#      km preddens
#   <int>    <dbl>
# 1     1     6.54
# 2     2     5.62
# 3     3     4.69
# 4     4     3.77
# 5     5     2.84

好的,那么我们如何得到一个单一的帧?

datpredonly <- datpred %>%
  select(city, pred) %>%
  unnest()
datpredonly
# # A tibble: 15 x 3
#    city     km preddens
#    <fct> <int>    <dbl>
#  1 city1     1     6.54
#  2 city1     2     5.62
#  3 city1     3     4.69
#  4 city1     4     3.77
#  5 city1     5     2.84
#  6 city2     1     6.37
#  7 city2     2     5.36
#  8 city2     3     4.36
#  9 city2     4     3.35
# 10 city2     5     2.34
# 11 city3     1     6.67
# 12 city3     2     5.70
# 13 city3     3     4.73
# 14 city3     4     3.76
# 15 city3     5     2.78

如果您想与原始版本进行比较(例如错误等),请尝试:

full_join(datlong, datpredonly, by = c("city", "km")) %>%
  arrange(city, km)
#     city km     dens preddens
# 1  city1  1 6.265509 6.543607
# 2  city1  2 5.908208 5.617601
# 3  city1  3 4.944675 4.691595
# 4  city1  4 3.500000 3.765589
# 5  city1  5       NA 2.839583
# 6  city2  1 6.372124 6.367239
# 7  city2  2 5.201682 5.361514
# 8  city2  3 4.660798 4.355788
# 9  city2  4 3.200000 3.350063
# 10 city2  5       NA 2.344337
# 11 city3  1 6.572853 6.671989
# 12 city3  2 5.898390 5.700119
# 13 city3  3 4.629114 4.728249
# 14 city3  4       NA 3.756380
# 15 city3  5       NA 2.784510

因此,您讨论了使用指数回归的方法:在运行的早期对lm的一次调用中对此进行了处理。随时可以从dens ~ km更改为特定的指数公式。

我已将所有内容分解为几个部分。这是长链。

predkm <- 1:5
datnestedmodels <- datlong %>%
  group_by(city) %>%
  nest(.key = "citydat") %>%
  mutate(
    model = map(citydat, ~ lm(dens ~ km, data = .x)),
    pred = map(model, ~ data_frame(km = predkm,
                                   preddens = predict(.x, newdata = data.frame(km=predkm))))
  )
datnestedmodels %>%
  select(city, pred) %>%
  unnest()

如果您喜欢(或需要)“宽”格式:

datnestedmodels %>%
  select(city, pred) %>%
  unnest() %>%
  spread(km, preddens, sep = "")
# # A tibble: 3 x 6
#   city    km1   km2   km3   km4   km5
#   <fct> <dbl> <dbl> <dbl> <dbl> <dbl>
# 1 city1  6.54  5.62  4.69  3.77  2.84
# 2 city2  6.37  5.36  4.36  3.35  2.34
# 3 city3  6.67  5.70  4.73  3.76  2.78