ПРИВЕТ Все, я плохо знаком с 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
}
но циклы берут навсегда.
Действительно цените свои мысли.
Большое спасибо.
Вы пробовали
"Merge?
"Объединить два фрейма данных по общим столбцам или именам строк, или выполнить другие варианты операций объединения баз данных. "
Кроме того, я предлагаю использовать небольшую локальную базу данных MySQL / PostgreSQL (RMySQL / RPostgreSQL), если вы постоянно используете составные PK или что-либо еще в качестве уникальных идентификаторов. На мой взгляд, SQL-перестановка данных и последующее использование data.frames из представления намного проще, чем циклическая обработка.
Это быстрее? (Я предполагаю, что комбинация 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)})
Я думаю, что ключом является векторизация и использование оператора % 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)
В общем, вам следует избегать цикла в R. Это намного быстрее, если ваш код работает с векторами.
Я бы использовал слияние, как это предлагает ran2. Вы можете установить all.x = T
(или all.y
или all
), чтобы получить все строки из одного (или другого или обоих) - кадров данных. Это быстро и, как правило, позволяет самостоятельно определить, какие поля нужно сопоставить. В противном случае вам нужно будет указать by.x
(и by.y
или by
) в качестве поля поиска. Судя по его словам, вам может потребоваться создать это поле самостоятельно (согласно комментарию Джона).
Затем вы можете фильтровать по дате.
Если у вас нет данных, которые реплицируются в 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)
Учитывая, что у вас проблемы с памятью, возможно, вам поможет сокращение 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)})