Последующие проходы цикла для интерполяции подсчетов населения не заполняют фрейм данных должным образом - логика неверна? - PullRequest
0 голосов
/ 09 июля 2019

У меня есть фрейм данных с 6 переменными:

Depr - это коэффициент с 6 уровнями («0», «1», «2», «3», «4», «5»)

Пол является фактором с 3 уровнями («Оба пола», «Женщины», «Мужчины»)

Возраст является фактором с 19 уровнями («00-04», «05-09»"," 10-14 "," 15-19 "," 20-24 "," 25-29 "," 30-34 "," 35-39 "," 40-44 "," 45-49 ","50-54", "55-59", "60-64", "65-69", "70-74", "75-79", "80-84", "85+", "Total")

GL - это фактор (географический уровень) с 5 уровнями («HPE», «KFLA», «LGL», «ON», «Regional»)

YR - целое число (год), их всего два - 2011 и 2016 (годы переписи)

А Pop - это число населения, целое число.

Фрейм данных настроен в длинном формате, где у меня есть подсчет населения для всех комбинаций факторов для каждого из двух лет.

Depr     Sex           Age      GL       YR        Pop
0        Both sexes   00-04     ON       2011      395     
0        Both sexes   00-04     ON       2016      5550
...
1        Both sexes   00-04     ON       2011      495
1        Both sexes   00-04     ON       2016      3923

Я хочу интерполировать для лет между 2011 и2016 (2012, 2013, 2014, 2015) для каждой строки в моем фрейме данных, чтобы я получил что-то вроде этого:

Depr     Sex           Age      GL       YR        Pop
0        Both sexes   00-04     ON       2011      395     
0        Both sexes   00-04     ON       2012      456
0        Both sexes   00-04     ON       2013      689
0        Both sexes   00-04     ON       2014      2354
0        Both sexes   00-04     ON       2015      3446
0        Both sexes   00-04     ON       2016      5550

Я настроил вложенные циклы и использую approx для линейной интерполяции.,

#create an empty dataframe to combine the results

fdepr <- data.frame(Depr = factor (levels = c("0", "1", "2", "3", "4", "5")), 
                    Sex = factor(levels = c("Both sexes", "Female", "Male")), 
                    Age = factor (levels = c("00-04", "05-09", "10-14", 
                    "15-19", "20-24", "25-29", "30-34", "35-39", "40-44", 
                    "45-49","50-54", "55-59", "60-64", "65-69", "70-74", "75- 
                     79", "80-84", "85+","Total")),
                    GL = factor(levels = c("HPE","KFLA","LGL","ON","Regional")), 
                    YR = integer(), 
                    Pop = integer())


#loops to subset Pop by grouping categories (depr is my original df)

for (i in unique(depr$Depr))
{ 
  for (j in unique(depr$Sex)) 
  {
    for (k in unique(depr$Age)) 
    {
      for (l in unique(depr$GL))  {
      temp <- subset(depr, subset=(Depr==i & Sex==j & Age==k & GL == l),select = c(YR, Pop))
      x <- temp$YR
      y <- temp$Pop
      t <- c(2011,2012,2013,2014,2015,2016)
      points <- approx(x,y, method = 'linear', xout=t)
      results <- data.frame(Depr=rep(i,6), Sex=rep(j,6), Age=rep(k,6), GL= rep(l,6), YR = points$x, Pop = points$y)
      fdepr <- rbind (fdepr,results)
    } 
  }}} 

Кажется, что он прошел и выполнил первый раунд нормально и заполнил results и fdepr, как и ожидалось, но затем я получил Error in approx(x, y, method = "linear", xout = t) : need at least two non-NA values to interpolate

temp пустои x и y.Я не уверен, что что-то определено в fdepr или проблема заключается во вложенных циклах ...

Я не ученый данных, поэтому сложная логика и программирование не интуитивны- любая оценка приветствуется

1 Ответ

1 голос
/ 09 июля 2019

По моему мнению, создание нового фрейма данных и выполнение вложенных циклов for делает это более сложным, чем это должно быть.

Здесь я использую group_by и expand, чтобы получить промежуточные годы для каждой из групп данных, затем left_join, используя исходный фрейм данных, чтобы добавить соответствующие значения Pop.После этого вам просто нужно применить na.approx к каждой группе данных, и данные уже сгруппированы из части expand, поэтому вы можете просто использовать mutate.

Конечно, вы можете переписать Pop в вызове mutate вместо создания новой переменной, я просто сделал это для наглядности.

library(zoo) # for na.approx
library(tidyverse) # for $>%, group_by, expand, left_join, and mutate

depr %>% 
  group_by(Depr, Sex, Age, GL) %>% 
  expand(YR = do.call(seq, as.list(YR))) %>% 
  left_join(depr, names(.)) %>% 
  mutate(Pop_interp = na.approx(Pop))

# # A tibble: 12 x 7
# # Groups:   Depr, Sex, Age, GL [2]
#     Depr Sex   Age   GL       YR   Pop Pop_interp
#    <int> <chr> <chr> <chr> <int> <int>      <dbl>
#  1     0 Both  00-04 ON     2011   395       395 
#  2     0 Both  00-04 ON     2012    NA      1426 
#  3     0 Both  00-04 ON     2013    NA      2457 
#  4     0 Both  00-04 ON     2014    NA      3488 
#  5     0 Both  00-04 ON     2015    NA      4519 
#  6     0 Both  00-04 ON     2016  5550      5550 
#  7     1 Both  00-04 ON     2011   495       495 
#  8     1 Both  00-04 ON     2012    NA      1181.
#  9     1 Both  00-04 ON     2013    NA      1866.
# 10     1 Both  00-04 ON     2014    NA      2552.
# 11     1 Both  00-04 ON     2015    NA      3237.
# 12     1 Both  00-04 ON     2016  3923      3923 

Вот то же самое сdata.table и magrittr вместо tidyverse

library(zoo)
library(magrittr)
library(data.table)

depr[, .(YR = do.call(seq, as.list(YR))), .(Depr, Sex, Age, GL)] %>% 
  .[depr, on = names(.), Pop := i.Pop] %>% 
  .[, Pop_Interp := na.approx(Pop)] %>% 
  print

#     Depr  Sex   Age GL   YR  Pop Pop_Interp
#  1:    0 Both 00-04 ON 2011  395      395.0
#  2:    0 Both 00-04 ON 2012   NA     1426.0
#  3:    0 Both 00-04 ON 2013   NA     2457.0
#  4:    0 Both 00-04 ON 2014   NA     3488.0
#  5:    0 Both 00-04 ON 2015   NA     4519.0
#  6:    0 Both 00-04 ON 2016 5550     5550.0
#  7:    1 Both 00-04 ON 2011  495      495.0
#  8:    1 Both 00-04 ON 2012   NA     1180.6
#  9:    1 Both 00-04 ON 2013   NA     1866.2
# 10:    1 Both 00-04 ON 2014   NA     2551.8
# 11:    1 Both 00-04 ON 2015   NA     3237.4
# 12:    1 Both 00-04 ON 2016 3923     3923.0

Используемые входные данные

depr <- data.table::fread('
Depr     Sex           Age      GL       YR        Pop
0        Both    00-04     ON       2011      395     
0        Both    00-04     ON       2016      5550
1        Both    00-04     ON       2011      495     
1        Both    00-04     ON       2016      3923
', data.table = F)
...