#r #dataframe #date #census #gather
Вопрос:
Я новичок в R и действительно борюсь с тем, что кажется простой проблемой (на которую я не смог найти ответов).
У меня есть относительно большая таблица данных, которая, по сути, включает в себя-людей-где они живут-что они делают-даты въезда-даты выезда. Моя цель состоит в том, чтобы получить текущую таблицу еженедельных переписей, в которой каждая неделя представлена в виде строки и столбца для каждой профессии и города, заполненного численностью населения на тот момент.
#MRE library(tidyverse) library(lubridate) data lt;- data.frame( first_names = c("joe", "sally", "bob", "frank", "susy"), move_in = as.Date(c("2020-01-01", "2021-01-04", "2020-04-01", "2018-12-20", "2019-10-12")), move_out = as.Date(c("2021-01-01", NA, "2021-10-01", NA, NA)), city = c("Denver", "Phoenix", "Austin", "Denver", "Seattle"), occupation = c("doctor", "doctor", "architect", "teacher", "teacher")) #what I've tried : cities = unique(data$city)[!is.na(unique(data$city))] occupations = unique(data$occupation)[!is.na(unique(data$occupation))] weeks lt;- (date = seq(from = as.Date("2020-12-27"), to = as.Date(today()), by="1 week")) census lt;- matrix(data=NA, nrows=44, ncols=12) for (i in seq(cities)){ for (j in seq(occupations)){ count lt;- data %gt;% filter(cities == i) %gt;% filter(occupations == j) %gt;% sapply(weeks, function(x) sum( ((as.Date(data$move_in)) lt;= as.Date(x) amp; (as.Date(data$move_out)) gt; as.Date(x))| ((as.Date(data$move_in)) lt;= as.Date(x) amp; is.na(data$move_out)))) census[j,x] lt;- count }}
Любая помощь будет очень признательна!
Ответ №1:
Вот возможное решение с использованием некоторых глаголов tidyverse, поскольку вы загрузили этот пакет. Мы перебираем недели, в течение которых вы заинтересованы в использовании map_dfr
функции, и за каждую неделю мы собираем подмножество людей, которые там используют ваше логическое утверждение выше. Затем мы можем использовать group_by
, чтобы пропустить двойной внешний цикл и count
их напрямую. Наконец, мы mutate
создали новую колонку на неделю, чтобы сохранить их сразу после того, как они будут связаны вместе. За пределами цикла мы затем pivot_wider
получим формат по одному столбцу на занятие и по одной строке в неделю, который вы ищете.
library(tidyverse) data lt;- data.frame( first_names = c("joe", "sally", "bob", "frank", "susy"), move_in = as.Date(c("2020-01-01", "2021-01-04", "2020-04-01", "2018-12-20", "2019-10-12")), move_out = as.Date(c("2021-01-01", NA, "2021-10-01", NA, NA)), city = c("Denver", "Phoenix", "Austin", "Denver", "Seattle"), occupation = c("doctor", "doctor", "architect", "teacher", "teacher")) # Avoid needing to load lubridate by using Sys.Date() instead of today() weeks lt;- (date = seq(from = as.Date("2020-12-27"), to = as.Date(Sys.Date()), by="1 week")) map_dfr(weeks, function(week_i){ data %gt;% filter(move_inlt;week_i amp; move_out gt; week_i | move_in lt; week_i amp; is.na(move_out)) %gt;% group_by(city, occupation) %gt;% count() %gt;% mutate(week=week_i) }) %gt;% pivot_wider(values_from = n, names_from = occupation, values_fill = 0)
который возвращает
# A tibble: 170 x 5 # Groups: city [4] city week architect doctor teacher lt;chrgt; lt;dategt; lt;intgt; lt;intgt; lt;intgt; 1 Austin 2020-12-27 1 0 0 2 Denver 2020-12-27 0 1 1 3 Seattle 2020-12-27 0 0 1 4 Austin 2021-01-03 1 0 0 5 Denver 2021-01-03 0 0 1 6 Seattle 2021-01-03 0 0 1 7 Austin 2021-01-10 1 0 0 8 Denver 2021-01-10 0 0 1 9 Phoenix 2021-01-10 0 1 0 10 Seattle 2021-01-10 0 0 1 # ... with 160 more rows
Похоже, вы получаете ошибки из-за пары опечаток. Вы используете filter
глагол, чтобы запросить cities
столбец, но в данных есть только city
столбец в образце набора данных. То же самое для occupations
vs occupation
. Хорошо иметь в виду на будущее, но отличное первое усилие и прекрасный пример!
Комментарии:
1. Это прекрасно работает! Большое вам спасибо за помощь, объяснение и совет.
Ответ №2:
Я использовал данные.таблица. lubridate
не требуется, я использовал Sys.Date().
Я также сделал перепись data.table вместо матрицы.
data.table::CJ почти такой же, как expand.grid.
Затем использовал mapply вместо циклов for.
Наконец, перестроен с длинного на широкий, как я думаю, это то, что вы хотели.
Я ушел во всех комбинациях city_occupation — не уверен, что это было намерением.
library(data.table) library(magrittr) data lt;- data.frame( first_names = c("joe", "sally", "bob", "frank", "susy"), move_in = as.Date(c("2020-01-01", "2021-01-04", "2020-04-01", "2018-12-20", "2019-10-12")), move_out = as.Date(c("2021-01-01", NA, "2021-10-01", NA, NA)), city = c("Denver", "Phoenix", "Austin", "Denver", "Seattle"), occupation = c("doctor", "doctor", "architect", "teacher", "teacher")) cities lt;- unique(data$city)[!is.na(unique(data$city))] occupations lt;- unique(data$occupation)[!is.na(unique(data$occupation))] weeks lt;- (date = seq(from = as.Date("2020-12-27"), to = Sys.Date(), by="1 week")) data %gt;% setDT() census lt;- CJ(week = weeks, city = cities, occupation = occupations) %gt;% .[, count := mapply(function(wk, cty, occ) { data[city == cty amp; occupation == occ, sum(move_in lt;= wk amp; (move_out gt; wk | is.na(move_out)))] }, week, city, occupation)] census %lt;gt;% dcast(week ~ city occupation, value.var = 'count')
Дает:
census week Austin_architect Austin_doctor Austin_teacher Denver_architect 1: 2020-12-27 1 0 0 0 2: 2021-01-03 1 0 0 0 3: 2021-01-10 1 0 0 0 4: 2021-01-17 1 0 0 0 5: 2021-01-24 1 0 0 0 6: 2021-01-31 1 0 0 0 7: 2021-02-07 1 0 0 0 8: 2021-02-14 1 0 0 0 9: 2021-02-21 1 0 0 0 10: 2021-02-28 1 0 0 0 11: 2021-03-07 1 0 0 0 12: 2021-03-14 1 0 0 0 13: 2021-03-21 1 0 0 0 14: 2021-03-28 1 0 0 0 15: 2021-04-04 1 0 0 0 16: 2021-04-11 1 0 0 0 17: 2021-04-18 1 0 0 0 18: 2021-04-25 1 0 0 0 19: 2021-05-02 1 0 0 0 20: 2021-05-09 1 0 0 0 21: 2021-05-16 1 0 0 0 22: 2021-05-23 1 0 0 0 23: 2021-05-30 1 0 0 0 24: 2021-06-06 1 0 0 0 25: 2021-06-13 1 0 0 0 26: 2021-06-20 1 0 0 0 27: 2021-06-27 1 0 0 0 28: 2021-07-04 1 0 0 0 29: 2021-07-11 1 0 0 0 30: 2021-07-18 1 0 0 0 31: 2021-07-25 1 0 0 0 32: 2021-08-01 1 0 0 0 33: 2021-08-08 1 0 0 0 34: 2021-08-15 1 0 0 0 35: 2021-08-22 1 0 0 0 36: 2021-08-29 1 0 0 0 37: 2021-09-05 1 0 0 0 38: 2021-09-12 1 0 0 0 39: 2021-09-19 1 0 0 0 40: 2021-09-26 1 0 0 0 41: 2021-10-03 0 0 0 0 42: 2021-10-10 0 0 0 0 43: 2021-10-17 0 0 0 0 44: 2021-10-24 0 0 0 0 week Austin_architect Austin_doctor Austin_teacher Denver_architect Denver_doctor Denver_teacher Phoenix_architect Phoenix_doctor 1: 1 1 0 0 2: 0 1 0 0 3: 0 1 0 1 4: 0 1 0 1 5: 0 1 0 1 6: 0 1 0 1 7: 0 1 0 1 8: 0 1 0 1 9: 0 1 0 1 10: 0 1 0 1 11: 0 1 0 1 12: 0 1 0 1 13: 0 1 0 1 14: 0 1 0 1 15: 0 1 0 1 16: 0 1 0 1 17: 0 1 0 1 18: 0 1 0 1 19: 0 1 0 1 20: 0 1 0 1 21: 0 1 0 1 22: 0 1 0 1 23: 0 1 0 1 24: 0 1 0 1 25: 0 1 0 1 26: 0 1 0 1 27: 0 1 0 1 28: 0 1 0 1 29: 0 1 0 1 30: 0 1 0 1 31: 0 1 0 1 32: 0 1 0 1 33: 0 1 0 1 34: 0 1 0 1 35: 0 1 0 1 36: 0 1 0 1 37: 0 1 0 1 38: 0 1 0 1 39: 0 1 0 1 40: 0 1 0 1 41: 0 1 0 1 42: 0 1 0 1 43: 0 1 0 1 44: 0 1 0 1 Denver_doctor Denver_teacher Phoenix_architect Phoenix_doctor Phoenix_teacher Seattle_architect Seattle_doctor Seattle_teacher 1: 0 0 0 1 2: 0 0 0 1 3: 0 0 0 1 4: 0 0 0 1 5: 0 0 0 1 6: 0 0 0 1 7: 0 0 0 1 8: 0 0 0 1 9: 0 0 0 1 10: 0 0 0 1 11: 0 0 0 1 12: 0 0 0 1 13: 0 0 0 1 14: 0 0 0 1 15: 0 0 0 1 16: 0 0 0 1 17: 0 0 0 1 18: 0 0 0 1 19: 0 0 0 1 20: 0 0 0 1 21: 0 0 0 1 22: 0 0 0 1 23: 0 0 0 1 24: 0 0 0 1 25: 0 0 0 1 26: 0 0 0 1 27: 0 0 0 1 28: 0 0 0 1 29: 0 0 0 1 30: 0 0 0 1 31: 0 0 0 1 32: 0 0 0 1 33: 0 0 0 1 34: 0 0 0 1 35: 0 0 0 1 36: 0 0 0 1 37: 0 0 0 1 38: 0 0 0 1 39: 0 0 0 1 40: 0 0 0 1 41: 0 0 0 1 42: 0 0 0 1 43: 0 0 0 1 44: 0 0 0 1 Phoenix_teacher Seattle_architect Seattle_doctor Seattle_teacher
Комментарии:
1. Спасибо тебе, Брайан, за помощь! Это решение полностью работает и помогло мне узнать кучу полезных вещей, которые я буду иметь в виду (об использовании mapply вместо циклов for и функции CJ). В конечном счете, когда я применил его к своему реальному набору данных, это заставило меня понять, что структурирование его так, как я изначально предполагал, привело к слишком большому количеству комбинаций «профессия-город», и он стал громоздким. Решение @Dubukay в конечном итоге сохранило «город» в виде столбца и привело к созданию более удобной таблицы для моих целей.