Додайте значення порожньому вектору в R?


160

Я намагаюся вивчити 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

тільки для наочності, це не так, як ви це зробили б у python, принаймні, якщо я вас правильно зрозумів. ви могли просто зробити vector = values; або ви можете зробити значення вектор = вектор +. Але я можу не зрозуміти вашу справу використання
рядовий

Відповіді:


209

Звернення до об'єкта в циклі for for призводить до того, що весь об'єкт буде скопійовано під час кожної ітерації, через що багато людей говорять "R повільно" або "R циклів слід уникати".

Як згадував BrodieG у коментарях: набагато краще заздалегідь виділити вектор потрібної довжини, а потім встановити значення елементів у циклі.

Ось кілька способів додавання значень до вектора. Усі вони зневажаються.

Додавання до вектора в циклі

# 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().

Попередньо виділіть вектор перед циклом

Якщо ви абсолютно повинні використовувати цикл 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
Я спробував це, але отримав NULL-список, коли я друкував (вектор)
O.rka

6
+1 для нагадування про неефективність, але, можливо, додайте подробиці про те, як обійти ( vector <- character(length(values)); for(...)?
BrodieG

20
Якщо всіх не відволікає, було б непогано підкреслити те, що рекомендується натомість, оскільки це досить поширена модель.
baxx

на цьому етапі, можливо, варто також згадати чудову книгу "R inferno", в якій обговорюються зростаючі вектори в колі 2 burns-stat.com/pages/Tutor/R_inferno.pdf
Tjebo

62

FWIW: аналог додатку python ():

b <- 1
b <- c(b, 2)

8
Існує також Append () в R. Буде використовуватися як: b <- 1; b <- append(b, 2). Але, як ви згадуєте, c () - це більш R-спосіб здійснення справ.
juanbretti

31

У вас є кілька варіантів:

  • c(vector, values)

  • append(vector, values)

  • vector[(length(vector) + 1):(length(vector) + length(values))] <- values

Перший - це стандартний підхід. Другий дає вам можливість прикласти десь інше, ніж кінець. Останній з них дещо викривлений, але має перевагу модифікувати vector(хоча насправді, ви могли так само легко зробити vector <- c(vector, values).

Зауважте, що в R вам не потрібно переходити через вектори. Ви можете просто оперувати ними цілком.

Крім того, це досить основні речі, тому вам слід ознайомитися з деякими посиланнями .

Ще кілька варіантів на основі зворотного зв’язку щодо ОП:

for(i in values) vector <- c(vector, i)

Я роблю щось трішки складніше. мені потрібно додати їх через for-loop, тому що я
змінюю

1
@ draconisthe0ry, чому б ви не надали більше деталей про те, що ви намагаєтесь зробити?
BrodieG

1
о Я бачу! замість того, щоб робити c (вектор, значення [i]) в циклі for, ви повинні "вектор = c (вектор, значення [i])"
O.rka

cгадаю, я хотів би використовувати для додавання фрейму даних замість векторів?
loretoparisi

18

Тільки задля повноти, додавання значень вектору в циклі for for насправді не є філософією в R. R. Перевірте, чи не можна ваш код переписати як:

ouput <- sapply(values, function(v) return(2*v))

Вихід буде вектором повернених значень. Ви також можете використовувати, lapplyякщо значення - це список, а не вектор.


8

Іноді нам доводиться використовувати петлі, наприклад, коли ми не знаємо, скільки ітерацій нам потрібно, щоб отримати результат. Візьмемо приклад циклів як приклад. Нижче наведено методи, яких слід абсолютно уникати:

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 копіює вектор кожного разу, коли він додається.

Найефективніший спосіб додавання - це використання індексу. Зверніть увагу , що на цей раз я нехай ітерація 1e7 раз, але він по - , як і раніше набагато швидше 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

2

У 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"

2
> 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"

0

Те, що ви використовуєте в коді python, називається списком у python, і він абсолютно відрізняється від R векторів, якщо я отримаю те, що ви хочете зробити:

# you can do like this if you'll put them manually  
v <- c("a", "b", "c")

# if your values are in a list 
v <- as.vector(your_list)

# if you just need to append
v <- append(v, value, after=length(v))
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.