как избежать циклов

ПРИВЕТ Все, я плохо знаком с R.

Я имею два файла данных панели, со столбцами "идентификатор", "дата" и "мочу"

файл A имеет намного больше данных, чем файл B, но я, прежде всего, работаю с данными файла B.

Комбинация "идентификатора" и "даты" является unqiue indentifier.

Существует ли изящный способ искать для каждого (идентификатор, дата) в B, я должен добраться, прошедшие 10 дней мочат из файла A и хранят их назад в B?

мой наивный способ сделать его состоит в том, чтобы циклично выполниться для всех строк в B,

for i in 1:length(B) {
    B$past10d[i] <- prod(1+A$ret[which(A$id == B$id[i] & A$date > B$date[i]-10 & A$date < B$date[i])])-1
}

но циклы берут навсегда.

Действительно цените свои мысли.

Большое спасибо.

6
задан Wok 24 September 2010 в 21:28
поделиться

6 ответов

Вы пробовали

"Merge?

"Объединить два фрейма данных по общим столбцам или именам строк, или выполнить другие варианты операций объединения баз данных. "

Кроме того, я предлагаю использовать небольшую локальную базу данных MySQL / PostgreSQL (RMySQL / RPostgreSQL), если вы постоянно используете составные PK или что-либо еще в качестве уникальных идентификаторов. На мой взгляд, SQL-перестановка данных и последующее использование data.frames из представления намного проще, чем циклическая обработка.

1
ответ дан 17 December 2019 в 20:28
поделиться

Это быстрее? (Я предполагаю, что комбинация B $ id и B $ date является уникальным идентификатором, нигде не реплицируемым - подразумевается вашим кодом)

B$idDate <- factor(B$id):factor(B$date)
B$past10 <- sapply(B$idDate, function(x){with(B[B$idDate == x,], 
    prod(1+A$ret[A$id == id & A$date > date-10 & A$date < date])-1)})
0
ответ дан 17 December 2019 в 20:28
поделиться

Я думаю, что ключом является векторизация и использование оператора % in% для подмножества фрейма данных A . И, я знаю, цены не случайные числа, но я не хотел кодировать случайное блуждание ... Я создал индекс даты запасов, используя paste , но я уверен, что вы могли бы использовать индекс из pdata.frame в библиотеке plm , что является лучшим, что я нашел для панельных данных.

A  <- data.frame(stock=rep(1:10, each=100), date=rep(Sys.Date()-99:0, 10), price=rnorm(1000))
B <- A[seq(from=100, to=1000, by=100), ]
A <- cbind(paste(A$stock, A$date, sep="-"), A)
B <- cbind(paste(B$stock, B$date, sep="-"), B)
colnames(A) <- colnames(B) <- c("index", "stock", "date", "price")
index <- which(A[, 1] %in% B[, 1])
returns <- (A$price[index] - A$price[index-10]) / A$price[index-10]
B <- cbind(B, returns)
1
ответ дан 17 December 2019 в 20:28
поделиться

В общем, вам следует избегать цикла в R. Это намного быстрее, если ваш код работает с векторами.

Я бы использовал слияние, как это предлагает ran2. Вы можете установить all.x = T (или all.y или all ), чтобы получить все строки из одного (или другого или обоих) - кадров данных. Это быстро и, как правило, позволяет самостоятельно определить, какие поля нужно сопоставить. В противном случае вам нужно будет указать by.x by.y или by ) в качестве поля поиска. Судя по его словам, вам может потребоваться создать это поле самостоятельно (согласно комментарию Джона).

Затем вы можете фильтровать по дате.

0
ответ дан 17 December 2019 в 20:28
поделиться

Если у вас нет данных, которые реплицируются в A и B, то rbind - самое простое решение.

#Sample data
A <- data.frame(
  id = rep(letters[1:3], each = 13),
  date = Sys.Date() + -12:0,
  ret = runif(39)
)

B <- data.frame(
  id = rep(letters[5:6], each = 5),
  date = Sys.Date() + -4:0,
  ret = runif(10)
)

#Only take the last ten days from A
A_past_10_days <- A[A$date > Sys.Date() - 10,]

#Bind by rows
rbind(A_past_10_days, B)
0
ответ дан 17 December 2019 в 20:28
поделиться

Учитывая, что у вас проблемы с памятью, возможно, вам поможет сокращение A. Сначала избавьтесь от лишних идентификаторов.

A <- A[A$id %in% B$id,]

Полное сокращение набора данных A все равно хочет занять больше памяти. Это невозможно без хранения некоторых переменных. Тем не менее, мы можем избавиться от кучи этих переменных, я надеюсь, отрезав каждую дату ниже нашего абсолютного минимума и выше нашего абсолютного максимума.

A <- A[A$date > (min(B$date) - 10) & A$date <= max(B$date),]

Конечно, не определяя это по id, мы не получили самую маленькую версию A из возможных, но, надеюсь, она достаточно маленькая.

Теперь запустите код, который я предложил первым, и посмотрите, осталась ли у вас ошибка памяти

B$idDate <- factor(B$id):factor(B$date)
B$past10 <- sapply(B$idDate, function(x){with(B[B$idDate == x,], 
    prod(1+A$ret[A$id == id & A$date > date-10 & A$date < date])-1)})
0
ответ дан 17 December 2019 в 20:28
поделиться
Другие вопросы по тегам:

Похожие вопросы: