Например: у меня есть фрейм данных с именем table:
Cn c1 c2 c3 c4
c3 1 3 5 6
c2 4 6 7 9
Я хочу создать новый столбец со значением, содержащимся в столбце, с именем столбца в Cn, чтобы он выглядел так:
Cn c1 c2 c3 c4 NewCol
c3 1 3 5 6 5
c2 4 6 7 9 6
Моя попытка была table$NewCol<-table[,table$Cn]
Однако вместо того, чтобы возвращать 1 значение для каждой строки, table$NewCol[1]
представляет собой вектор, содержащий (5, 3), который ссылается на (c3, c2) в столбце Cn, что означает, что для каждой строки все строки Cn ищутся и помещаются в новую переменную.
Я знаю, что могу использовать циклы, но я имею дело с фреймом данных с более чем 7 миллионами записей, и цикл выполняется очень медленно.
У кого-нибудь есть идеи, как с этим бороться?
2 ответа
Используйте матричную индексацию нужных значений строки и столбца для извлечения. Я использовал dat
в качестве имени вашего data.frame.
dat[-1][cbind(seq_along(dat$Cn),match(as.character(dat$Cn),names(dat[-1])))]
#[1] 5 6
Как в:
sel <- cbind(seq_along(dat$Cn),match(as.character(dat$Cn),names(dat[-1])))
sel
# row col
# [,1] [,2]
#[1,] 1 3
#[2,] 2 2
dat[-1][sel]
#[1] 5 6
Время для 7M строк и вашего примера с 4 столбцами составляет около 0,4 секунды.
dat2 <- dat[sample(1:2,7e6,replace=TRUE),]
nrow(dat2)
#[1] 7000000
system.time({
sel <- cbind(seq_along(dat2$Cn),match(as.character(dat2$Cn),names(dat2[-1])))
dat2$newcol <- dat2[-1][sel]
})
# user system elapsed
# 0.33 0.07 0.39
set
будет заключаться в эффективности использования памяти (нет необходимости создавать 7-миллионную матрицу строк sel
)
data.table
нет матричной индексации, вы всегда можете разрезать это решение на управляемые блоки из нескольких сотен тысяч строк в цикле. Запуск по-прежнему займет всего несколько секунд, и это позволит избежать необходимости назначать огромную матрицу.
Используйте mapply
, чтобы применить [.data.frame
при перемещении по каждой строке и d $ Cn.
table$NewCol <- mapply(i = seq_along(d[['Cn']]),
j= d[['Cn']],
FUN = function(i,j,x) x[i,j,drop=TRUE],
MoreArgs=list(x=d))
Если скорость и эффективность вызывают беспокойство, используйте data.table
и set
(этот цикл является эффективным)
library(data.table)
setDT(d)
for(i in seq_len(nrow(d))){
set(d,j='newCol', i=i, value= d[[d[['Cn']][i]]][i])
}
data.table
. Я предполагаю, что это будет меньше одной минуты.
data.table
и set
занимает около 1 минуты с 50 столбцами и 1 миллионом строк....
Похожие вопросы
Новые вопросы
r
R — это бесплатный язык программирования с открытым исходным кодом и программная среда для статистических вычислений, биоинформатики, визуализации и общих вычислений. Пожалуйста, используйте минимально воспроизводимые примеры, которые другие могут запустить с помощью копирования и вставки. Показать желаемый результат. Используйте dput() для данных и укажите все небазовые пакеты с помощью library(). Не вставляйте изображения для данных или кода, вместо этого используйте блоки кода с отступом. Для вопросов по статистике используйте https://stats.stackexchange.com.
df$NewCol <- diag(as.matrix(df[match(df$Cn, names(df))]))
, гдеdf
— данные