2010-07-12 4 views
6

Привет всем, Я новичок в R.как избежать петли

У меня есть два файла данных панели, с колоннами «ID», «дата» и «РЭТ»

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

Сочетание «id» и «date» - это indqifier.

Есть ли изящный способ поиска каждого (id, date) в B, мне нужно получить последние 10 дней ret из файла 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 
} 

но петли принимает навсегда.

Наслаждайтесь своими мыслями.

спасибо.

+1

K: Для дальнейшего использования: Это очень полезно для людей, которые пытаются помочь вам, если ваш код совпадает с текстом вопроса ты спрашиваешь. –

+1

sry my bad. спасибо за вашу помощь –

+0

Открыта для интерпретации, соответствует ли она или нет. Код - это просто пояснение ... как обычно. – John

ответ

0

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

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

благодарит за ответ john. Это выглядит очень аккуратно. Но когда я пробовал данные, я получил: Ошибка: не могу выделить вектор размером 6.8 Mb слишком много работы для парня B $ past10? –

+0

Это не должно быть намного более интенсивным в памяти, чем ваш метод. Попробуйте очистить некоторые вещи в памяти с помощью команд ls() и rm(). Или попробуйте перезапустить R и выполнить снова. – John

+0

tks! я попробую это .. но я забыл упомянуть, что мой наивный метод никогда не заканчивал цикл ...: S –

1

Пробовали ли вы объединить?

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

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

+0

hm .. Мне, возможно, придется заглянуть в sql. спасибо! –

+0

RMySQL было проще начать с ... –

0

Если у вас нет данных, которые реплицируются как в 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

Вы занимаете последние 10 дней с сегодняшнего дня, но его код занимает последние 10 дней с каждой возможной даты в B, определяемой идентификатором, который идет с этой датой. – John

+0

@John: Хорошо пятнистый. Кажется, я ответил на текст вопроса, но не на вопрос, скрытый в коде. ** Sigh ** –

0

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

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

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

+0

tks! B на самом деле намного меньше подмножества A, поэтому, если я правильно понимаю «merge», то A будет результатом слияния. –

+0

Это займет гораздо больше памяти, чем ваше оригинальное решение. Учитывая, что вы выбрали ограничения по памяти с моим предложением, это вряд ли сработает. Кроме того, все это делает вам данные в одном месте. Это не решает вашу проблему превращения этих последних 10 дней в одно значение ... которое предлагает ваш код. – John

+0

Ах! Виноват. Я думал, что вы получаете набор строк от A до B. Я не понял, что вы действительно хотели обобщить продукт.Вы также можете быть заинтересованы в совокупности (функция удобства для sapply). Если у вас проблемы с памятью, вы можете захотеть подмножества взять небольшой образец, на который вы можете практиковать, пока не убедитесь, что код работает (см. Также: http://www.r-bloggers.com/memory-management -в-ра-несколько-советы-и-трик /). – RobinGower

1

Я думаю, что ключ заключается в векторизации и использовании оператора %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) 
0

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

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

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

A <- A[A$date > (min(B$date) - 10) & A$date <= max(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

Спасибо, Джон, две линии помогают сократить много в А., но после того, как я попробовал всего 500 строк, это все равно дало мне ошибку: не может выделить вектор размером 6.8 Мб. Я думаю, что проблема может быть в «sapply». каким-то образом он принимает идентификатор и дату в качестве вектора и пытается сравнить A $ id с B $ id и т. д., а не с помощью элемента –

+0

выглядит как sapply (B $ idDate), который создает проблему, я изменил B $ idDate на символы и код работает ........ пахнет как петля –

+0

попробуйте не ставить past10 в B (удалить B $ в начале второй строки). У вас тоже проблема с памятью? sapply() принимает каждый элемент B, а затем использует его для подбора A и получения продукта ... как в вашем исходном коде. Я продемонстрировал это на своем коде, но на моем компьютере 6.8meg - это тривиальный объем памяти (и я использую только около 200 строк). И если он сообщает сообщение об ошибке, то какое именно сообщение? – John

0
library(data.table) 
#create data 
A <- data.table(id=rep(1:10, each=40000), date=rep(Sys.Date()-99:0, 4000), ret=rnorm(400000)) 
B <- data.table(id=rep(1:5, each=10), date=rep(Sys.Date()-99:0), ret=rnorm(50)) 

#find dates to compare against 
n <- NROW(B) 
B_long <- B[,.(id = rep(id,each=10),date = rep(date,each=10))] 
s <- rep(-10:-1,n) 
B_long[,date:=date + s] 

#information in one column 
B_long$com <- as.numeric(paste0(B_long$id,as.numeric(B$date))) 
A$com <- as.numeric(paste0(A$id,as.numeric(A$date))) 

#compare 
setkey(A,com) 
X <- A[com %in% B_long$com,] 

Этот ответ опирается на Richards ответ, но более целенаправленный на вопрос.

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

Мое решение использует пакет data.table, но с некоторыми изменениями синтаксиса работает с data.frame. Но использование пакета data.table имеет преимущество ключевых столбцов.

Если у вас есть проблемы вы можете спарить этот подход со вторым ответом Джона и первого урожая А.

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

  • Нет связанных вопросов^_^