2016-07-26 2 views
1

I have read, что добавление к векторам в R - плохая практика. В этом случае, что мне делать, когда я хочу создать вектор, но я не знаю его длины раньше времени?Как создать вектор в R, если вы не знаете длины раньше времени?

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

# loc id  time 
# 1: z A  00:00 
# 2: z A  00:01 
# 3: z B  00:02 
# 4: z A  00:02 
# 5: z C  00:05 
# 6: z C  00:07 
# 7: z A  00:08 
# 8: z A  00:09 
# 9: z C  00:09 
#10: z C  00:10 

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

# loc id starttime endtime 
# 1: z A  00:00 00:02 
# 2: z C  00:05 00:07 
# 3: z A  00:08 00:09 
# 4: z C  00:09 00:10 

Они могут быть 50 записей для одного человека в первом кадре данных, которые могут быть составлены в 3 «визитов» в новом кадре данных. Я не знаю заранее, сколько «посещений» есть. Итак, как мне нужно создавать этот фрейм данных?

Я знаю rbind, но в этом случае я буду привязывать каждую строку по одной. Это хорошая идея?

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

+0

Вы только что сделали, а затем добавите к нему. Вот как это делают динамические языки. Это имеет большее значение в целом при расширении больших списков, требующих копий. Более маленькие векторы и значение R уже закладываются за вашей спиной. –

+1

Это звучит немного похоже на то, что вы просто хотите «расплавить» и «фильтровать» ... без конкретного примера данных, однако это трудно понять. –

+1

Предлагаю вам главу 2 «Растущие объекты», это именно то, о чем вы просите :) http://www.burns-stat.com/pages/Tutor/R_inferno.pdf Решение, которое он предлагает, - это предложение, предложенное компанией @Roland, но он анализирует и другие методы с системным временем, используемым для выполнения определенных задач (вырастает в куске против rbind против индекса). Вы cn – Eugen

ответ

4

Я не уверен, что вам нужно это (есть, вероятно, лучшее решение для вашей плохо описанной актуальной проблемы), но я отвечу на вопрос в первом абзаце. Если вы не знаете, насколько велик вектор результатов, вы инициализируете его до разумного размера и вырабатываете его в кусках по мере необходимости. Это ограничивает время, в течение которого вектор нужно выращивать.

set.seed(42) 
vec <- numeric(100) #initialize a chunk 
i <- 0 

repeat { 
    test <- rnorm(1) 
    if (test > 3) break 
    i <- i + 1 
    #grow in chunks: 
    if (length(vec) < i) vec <- c(vec, numeric(100)) 
    vec[i] <- test 
} 

#shorten to final length 
vec <- vec[seq_len(i)] 

Вы действительно делаете что-то подобное в реальном времени. Если вы покупаете новую полку, вы покупаете ее достаточно большой, чтобы у вас было место для покупки книг в будущем. Когда он заполнен, вы покупаете следующий (или более крупный).

+0

Я никогда не видел 'repeat' used - очень элегантный! – dayne

1

Это явно не отвечает на ваш вопрос, но демонстрирует, как вы можете просто создать нужные данные, используя cut, чтобы создать «посещений», а затем подсчитывать уникальное количество посещений.

library(data.table) 
set.seed(1234) 
dat <- data.table(visit_time = sample(20, 100, replace = TRUE), 
        id = sample(LETTERS[1:5], 100, replace = TRUE)) 
dat[ , visit := cut(visit_time, breaks = seq(0, 20, 5))] 
dat[ , list(nvisits = length(unique(visit))), by = id] 
# id nvisits 
# 1: A  4 
# 2: C  4 
# 3: B  4 
# 4: D  4 
# 5: E  4 

Запуск следующих показывает, сколько раз они были на месте в том же TimeSpan/визита:

dat[ , .N, by = list(id, visit)] 
#  id visit N 
# 1: A (0,5] 6 
# 2: C (10,15] 5 
# 3: B (10,15] 6 
# 4: A (15,20] 3 
# 5: A (10,15] 5 
# 6: D (10,15] 6 
# 7: E (5,10] 7 
# 8: B (5,10] 6 
# 9: E (15,20] 4 
# 10: D (0,5] 6 
# 11: D (5,10] 4 
# 12: E (0,5] 9 
# 13: C (0,5] 4 
# 14: B (15,20] 1 
# 15: C (15,20] 9 
# 16: B (0,5] 6 
# 17: A (5,10] 2 
# 18: C (5,10] 5 
# 19: D (15,20] 2 
# 20: E (10,15] 4 

Edit, чтобы показать, как функция вырезать будет работать со временем:

Я взял randTime функцию от this excellent answer.

randTime <- function(N, st, et) { 
    st <- as.POSIXct(st) 
    et <- as.POSIXct(et) 
    dt <- as.numeric(difftime(et,st,unit="sec")) 
    ev <- sort(runif(N, 0, dt)) 
    rt <- st + ev 
    rt 
} 

set.seed(1234) 
st <- as.POSIXct("2012/01/01 12:00") 
et <- as.POSIXct("2012/01/01 18:00") 
dat2 <- data.table(visit_time = randTime(100, st, et), 
        id = sample(LETTERS[1:5], 100, replace = TRUE)) 
dat2[ , visit := as.character(cut(visit_time, breaks = seq(st, et, "15 min")))] 
dat2[ , length(unique(visit)), by = id] 
# id V1 
# 1: A 11 
# 2: C 13 
# 3: B 14 
# 4: D 14 
# 5: E 14 
+0

Сократили бы работу с POSIXt или POSIXct? – oregano

+0

Да. Я могу отредактировать ответ, чтобы показать вам, но @Roland действительно ответил на заданный вами вопрос. – dayne

+0

т. Е. Вы действительно должны принять его ответ, используете ли вы предоставленное мной решение или нет. – dayne

Смежные вопросы