как избежать петель - PullRequest
       11

как избежать петель

6 голосов
/ 12 июля 2010

Привет все, Я новичок в Р.

У меня есть два файла данных панели со столбцами «id», «date» и «ret»

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

Комбинация "id" и "date" является уникальным идентификатором.

Есть ли способ поиска каждого (id, даты) в 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
}

но цикл занимает вечность.

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

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

Ответы [ 7 ]

1 голос
/ 12 июля 2010

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

Вы пробовали? Объединить?

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

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

0 голосов
/ 06 апреля 2016
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,]

Этот ответ основан на ответе Ричардса, но более нацелен на вопрос.

Ключевой идеей является построение одного вектора комбинаций идентификаторов даты для сравнения. Это происходит во втором блоке кода.

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

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

0 голосов
/ 13 июля 2010

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

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

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

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

Конечно, не квалифицируя это по идентификатору, который у нас есть.Получите наименьшую возможную версию 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 голосов
/ 12 июля 2010

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

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

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

0 голосов
/ 12 июля 2010

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

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

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