Добавить значение в пустой вектор в R?
Я пытаюсь изучить R, и я не могу понять, как добавить в список.
Если бы это был Python, я бы это сделал.,.
#Python
vector = []
values = ['a','b','c','d','e','f','g']
for i in range(0,len(values)):
vector.append(values[i])
Как вы это делаете в R?
#R Programming
> vector = c()
> values = c('a','b','c','d','e','f','g')
> for (i in 1:length(values))
+ #append value[i] to empty vector
Ответы
Ответ 1
Вот несколько способов сделать это. Все они обескуражены. Добавление к объекту в цикле for приводит к тому, что весь объект копируется на каждой итерации, что заставляет многих людей говорить, что "R медленный" или "R-циклы следует избегать".
# one way
for (i in 1:length(values))
vector[i] <- values[i]
# another way
for (i in 1:length(values))
vector <- c(vector, values[i])
# yet another way?!?
for (v in values)
vector <- c(vector, v)
# ... more ways
help("append")
ответил бы на ваш вопрос и сэкономил время, которое потребовалось вам, чтобы написать этот вопрос (но вызвало бы у вас развитие вредных привычек).; -)
Заметим, что vector <- c()
не является пустым вектором; это NULL
. Если вам нужен пустой вектор символов, используйте vector <- character()
.
Также обратите внимание, что BrodieG указал в комментариях: если вы абсолютно должны использовать цикл for, то по крайней мере предварительно выделите весь вектор до петля. Это будет намного быстрее, чем добавление для больших векторов.
set.seed(21)
values <- sample(letters, 1e4, TRUE)
vector <- character(0)
# slow
system.time( for (i in 1:length(values)) vector[i] <- values[i] )
# user system elapsed
# 0.340 0.000 0.343
vector <- character(length(values))
# fast(er)
system.time( for (i in 1:length(values)) vector[i] <- values[i] )
# user system elapsed
# 0.024 0.000 0.023
Ответ 2
FWIW: аналогично python append():
b <- 1
b <- c(b, 2)
Ответ 3
У вас есть несколько вариантов:
Первый - это стандартный подход. Второй дает вам возможность добавить куда-нибудь еще, кроме конца. Последнее немного искажено, но имеет преимущество в изменении vector
(хотя на самом деле вы могли бы также легко сделать vector <- c(vector, values)
.
Обратите внимание, что в R вам не нужно перебирать векторы. Вы можете просто оперировать ими в целом.
Кроме того, это довольно простой материал, поэтому вам следует ознакомиться с некоторыми ссылками.
Еще несколько опций, основанных на обратной связи с OP:
for(i in values) vector <- c(vector, i)
Ответ 4
Только для полноты добавление значений к вектору в цикле for на самом деле не является философией R. R работает лучше, работая на векторах в целом, как отметил @BrodieG. Посмотрите, нельзя ли переписать код:
ouput <- sapply(values, function(v) return(2*v))
Вывод будет вектором возвращаемых значений. Вы также можете использовать lapply
, если значения представляют собой список вместо вектора.
Ответ 5
Иногда нам приходится использовать циклы, например, когда мы не знаем, сколько итераций нам нужно получить. Возьмем в качестве примера петли. Ниже приведены методы, которые вам следует избегать:
a=numeric(0)
b=1
system.time(
{
while(b<=1e5){
b=b+1
a<-c(a,pi)
}
}
)
# user system elapsed
# 13.2 0.0 13.2
a=numeric(0)
b=1
system.time(
{
while(b<=1e5){
b=b+1
a<-append(a,pi)
}
}
)
# user system elapsed
# 11.06 5.72 16.84
Это очень неэффективно, потому что R копирует вектор каждый раз, когда он добавляет.
Наиболее эффективным способом добавления является использование индекса. Обратите внимание, что на этот раз я пропустил его итерацию 1 раз, но он все еще намного быстрее, чем c
.
a=numeric(0)
system.time(
{
while(length(a)<1e7){
a[length(a)+1]=pi
}
}
)
# user system elapsed
# 5.71 0.39 6.12
Это приемлемо. И мы можем сделать это немного быстрее, заменив [
на [[
.
a=numeric(0)
system.time(
{
while(length(a)<1e7){
a[[length(a)+1]]=pi
}
}
)
# user system elapsed
# 5.29 0.38 5.69
Возможно, вы уже заметили, что length
может занять много времени. Если мы заменим length
на счетчик:
a=numeric(0)
b=1
system.time(
{
while(b<=1e7){
a[[b]]=pi
b=b+1
}
}
)
# user system elapsed
# 3.35 0.41 3.76
Как отмечают другие пользователи, предварительное выделение вектора очень полезно. Но это компромисс между скоростью и использованием памяти, если вы не знаете, сколько циклов вам нужно, чтобы получить результат.
a=rep(NaN,2*1e7)
b=1
system.time(
{
while(b<=1e7){
a[[b]]=pi
b=b+1
}
a=a[!is.na(a)]
}
)
# user system elapsed
# 1.57 0.06 1.63
Промежуточный метод заключается в постепенном добавлении блоков результатов.
a=numeric(0)
b=0
step_count=0
step=1e6
system.time(
{
repeat{
a_step=rep(NaN,step)
for(i in seq_len(step)){
b=b+1
a_step[[i]]=pi
if(b>=1e7){
a_step=a_step[1:i]
break
}
}
a[(step_count*step+1):b]=a_step
if(b>=1e7) break
step_count=step_count+1
}
}
)
#user system elapsed
#1.71 0.17 1.89
Ответ 6
В R вы можете попробовать:
X = NULL
X
# NULL
values = letters[1:10]
values
# [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
X = append(X,values)
X
# [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j"
X = append(X,letters[23:26])
X
# [1] "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "w" "x" "y" "z"
Ответ 7
> vec <- c(letters[1:3]) # vec <- c("a","b","c") ; or just empty vector: vec <- c()
> values<- c(1,2,3)
> for (i in 1:length(values)){
print(paste("length of vec", length(vec)));
vec[length(vec)+1] <- values[i] #Appends value at the end of vector
}
[1] "length of vec 3"
[1] "length of vec 4"
[1] "length of vec 5"
> vec
[1] "a" "b" "c" "1" "2" "3"