Эффективно обновите столбец данных, используя метод hashmap в R - PullRequest
3 голосов
/ 07 января 2012

Я новичок в R и не могу понять, что я могу делать неправильно в приведенном ниже коде и как я могу ускорить его. У меня есть набор данных, и я хотел бы добавить столбец, содержащий среднее значение, рассчитанное из двух столбцов данных. Пожалуйста, взгляните на код ниже (ВНИМАНИЕ: чтение моего вопроса может занять некоторое время, но код отлично работает на R):

сначала позвольте мне определить набор данных df (еще раз прошу прощения за длинное описание кода)

> df<-data.frame(prediction=sample(c(0,1),10,TRUE),subject=sample(c("car","dog","man","tree","book"),10,TRUE))
> df
   prediction subject
1           0     man
2           1     dog
3           0     man
4           1    tree
5           1     car
6           1    tree
7           1     dog
8           0    tree
9           1    tree
10          1    tree

Затем я добавляю новый столбец с именем subjectRate в df

.
df$subjectRate <- with(df,ave(prediction,subject))
> df
       prediction subject subjectRate
    1           0     man         0.0
    2           1     dog         1.0
    3           0     man         0.0
    4           1    tree         0.8
    5           1     car         1.0
    6           1    tree         0.8
    7           1     dog         1.0
    8           0    tree         0.8
    9           1    tree         0.8
    10          1    tree         0.8

из нового определения таблицы я генерирую карту скорости, чтобы автоматически заполнять новые данные столбцом subjectRate, инициализированным ранее полученным средним значением.

rateMap <- df[!duplicated(df[, c("subjectRate")]), c("subject","subjectRate")]
> rateMap
  subject subjectRate
1     man         0.0
2     dog         1.0
4    tree         0.8

Теперь я определяю новый набор данных с комбинацией старого предмета в df и новых предметов

> dfNew<-data.frame(prediction=sample(c(0,1),15,TRUE),subject=sample(c("car","dog","man","cat","book","computer"),15,TRUE))
> dfNew
   prediction  subject
1           1      man
2           0      cat
3           1 computer
4           0      dog
5           0     book
6           1      cat
7           1      car
8           0     book
9           0 computer
10          1      dog
11          0      cat
12          0     book
13          1      dog
14          1      man
15          1      dog

Мой вопрос: Как эффективно создать третий столбец? В настоящее время я запускаю тест, приведенный ниже, где я смотрю предметную карту на карте и вводю значение, если найдено, или 0,5, если нет.

> all_facts<-levels(factor(rateMap$subject))
> dfNew$subjectRate <-  sapply(dfNew$subject,function(t) ifelse(t %in% all_facts,rateMap[as.character(rateMap$subject) == as.character(t),][1,"subjectRate"],0.5))
> dfNew
   prediction  subject subjectRate
1           1      man         0.0
2           0      cat         0.5
3           1 computer         0.5
4           0      dog         1.0
5           0     book         0.5
6           1      cat         0.5
7           1      car         0.5
8           0     book         0.5
9           0 computer         0.5
10          1      dog         1.0
11          0      cat         0.5
12          0     book         0.5
13          1      dog         1.0
14          1      man         0.0
15          1      dog         1.0

, но с реальным набором данных (более 200 000 строк) с несколькими столбцами, подобными subject для вычисления среднего, выполнение кода занимает очень много времени. Может кто-нибудь предложить, может быть, лучший способ сделать то, что я пытаюсь достичь? может быть, какое-то слияние или что-то, но у меня нет идей. Спасибо.

1 Ответ

6 голосов
/ 07 января 2012

Я подозреваю (но не уверен, так как я не проверял это), что это будет быстрее:

dfNew$subjectRate <- rateMap$subjectRate[match(dfNew$subject,rateMap$subject)]

, поскольку он в основном использует только индексирование и match. Это, конечно, немного проще, я думаю. Это заполнит «новые» значения с NA с, а не с 0,5, которые затем могут быть заполнены, как вам нравится,

dfNew$subjectRate[is.na(dfNew$subjectRate)] <- newValue

Если фрагмент ave особенно медленный, в наши дни стандартная рекомендация - использовать пакет data.table :

require(data.table)
dft <- as.data.table(df)
setkeyv(dft, "subject")
dft[, subjectRate := mean(prediction), by = subject]

и это, вероятно, привлечет несколько комментариев, предлагающих способы получить немного больше скорости от агрегирования этой таблицы данных в последней строке. Действительно, объединение или объединение с использованием чистого data.tables может быть даже более плавным (и быстрым), поэтому вы можете также изучить эту опцию. (В самом низу ?data.table приведено несколько примеров.)

...