2015-02-26 3 views
1

Я закодирован функцию, которая преобразует атомный символ с атомным номером ...Для Loop One Too Long

AtomicNo <- function(x) { 
    y <- NULL 
    for (i in seq(along=x)) { 
    if (x[i] == "H") y[i] <- 1.0 else 
     if (x[i] == "C") y[i] <- 6.0 else 
     if (x[i] == "O") y[i] <- 8.0 else 
      if (x[i] == "Fe") y[i] <- 26.0 else 
      if (x[i] == "Br") y[i] <- 35.0 
    y <- append(y,y[i]) 
    } 
    return(y) 
    } 

Для вектора

a <- c("Fe", "Br", "O", "O", "C", "H", "H", "H", "C", "H", "H", "H", 
     "C", "H", "H", "H", "C", "H", "H", "H") 

AtomicNo (а) дает

26 35 8 8 6 1 1 1 6 1 1 1 6 1 1 1 6 1 1 1 1 

То есть, в конце вектора есть лишний 1, должно быть только три 1 с, а не четыре.

Может ли кто-нибудь увидеть, где я ошибаюсь?

ответ

5

Для простого перекодирования вы можете использовать вектор индексации вместе с элементами, давая имена

code <- c("H" = 1.0, "C" = 6.0, "O" = 8.0, "Fe" = 26.0, "Br" = 35.0) 
a <- c("Fe", "Br", "O", "O", "C", "H", "H", "H", "C", "H", "H", "H", "C", "H", "H", "H", "C", "H", "H", "H") 
code[a] 
#Fe Br O O C H H H C H H H C H H H C H H H 
#26 35 8 8 6 1 1 1 6 1 1 1 6 1 1 1 6 1 1 1 
## If you don't want the names... 
unname(code[a]) 
# [1] 26 35 8 8 6 1 1 1 6 1 1 1 6 1 1 1 6 1 1 1 

Edit:

А почему вы получаете дополнительный 1 на конце - это связано с вашим кодом.Взгляните на первые несколько итераций разворачивал

> y <- NULL 
> y[1] <- 26 
> y <- append(y, y[1]) 
> y 
[1] 26 26 
> y[2] <- 35 
> y <- append(y, y[2]) 
> y 
[1] 26 35 35 

В основном вы непосредственно настройки последнего элемента, а затем и решив добавить его к концу. На следующей итерации, которая добавляет элемент, будет перезаписана, но для самой последней итерации нет ничего, чтобы перезаписать дополнительный элемент в конце, чтобы вы получили дублирующее значение для последнего.

3

Нет необходимости добавлять y в конце вашей функции. Просто удалите это, и вы должны быть хорошо

AtomicNo <- function(x) { 
    y <- NULL 
    for (i in seq(along=x)) { 
    if (x[i] == "H") y[i] <- 1.0 else 
     if (x[i] == "C") y[i] <- 6.0 else 
     if (x[i] == "O") y[i] <- 8.0 else 
      if (x[i] == "Fe") y[i] <- 26.0 else 
      if (x[i] == "Br") y[i] <- 35.0 
    } 
    return(y) 
} 
+0

спасибо, отсортировано. Будет тикать через десять минут @CactusWoman – user1945827

5

Вы можете найти его проще (или, по крайней мере, менее типирование), чтобы использовать функцию recode из упаковки автомобиля:

library(car) 
recode(a, "'H'=1;'C'=6;'O'=8;'Fe'=26;'Br'=35;") 
# [1] 26 35 8 8 6 1 1 1 6 1 1 1 6 1 1 1 6 1 1 1 

Если вы хотите остаться в основание R, то вы найдете функцию ifelse быть намного более эффективным с очень похожим синтаксисом:

atomic.ifelse <- function(x) { 
    ifelse(x == "H", 1, 
    ifelse(x == "C", 6, 
     ifelse(x == "O", 8, 
     ifelse(x == "Fe", 26, 
      ifelse(x == "Br", 35, NA))))) 
} 

recode, ifelse, й match должен быть намного более эффективным, чем for петли с if заявление (добавление atomic.if от @CactusWoman, atomic.match от @MaratTalipov и atomic.index от @Dason):

big.a <- rep(a, 1000) 
all.equal(atomic.if(big.a), atomic.recode(big.a), atomic.ifelse(big.a), atomic.match(big.a), atomic.index(big.a)) 
# [1] TRUE 
library(microbenchmark) 
microbenchmark(atomic.if(big.a), atomic.recode(big.a), atomic.ifelse(big.a), atomic.match(big.a), atomic.index(big.a)) 
# Unit: microseconds 
#     expr  min   lq  mean  median   uq   max neval 
#  atomic.if(big.a) 753887.018 823974.2900 887305.3812 876902.6380 924005.505 1836067.802 100 
# atomic.recode(big.a) 8748.951 9129.5230 10694.0044 9299.0145 9617.688 116548.870 100 
# atomic.ifelse(big.a) 26329.875 27568.6540 30005.9327 28635.7760 29652.327 133560.908 100 
# atomic.match(big.a) 210.846 257.7595 370.9925 296.4305 343.732 2434.733 100 
# atomic.index(big.a) 527.043 616.7620 1013.0317 876.6060 1077.634 3371.246 100 

векторизации recode, ifelse, match, а векторная индексация обеспечила ускорение 30-3000x по петле for даже на этом относительно небольшом векторе (длина 20 000). match и индексирование векторов, по-видимому, являются победителями с точки зрения эффективности (15-30 раз быстрее, чем recode), так что это будет путь для очень больших векторов.

6

Вместо использования нескольких ifelse, вы можете просто сделать:

elements <- c("H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na", "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Sb", "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th", "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm", "Md", "No", "Lr", "Rf", "Db", "Sg", "Bh", "Hs", "Mt", "Ds", "Rg", "Cn", "Uut", "Fl", "Uup", "Lv", "Uus", "Uuo") 

(это полезно для химика, чтобы иметь список элементов в любом случае)

, а затем:

> match(a,elements) 
[1] 26 35 8 8 6 1 1 1 6 1 1 1 6 1 1 1 6 1 1 1 

Вот контрольный показатель:

> microbenchmark(f.match(big.a), atomic.recode(big.a), atomic.ifelse(big.a)) 
Unit: microseconds 
       expr  min  lq  mean median  uq  max neval cld 
     f.match(big.a) 205.090 252.345 280.8174 279.556 305.683 384.358 100 a 
atomic.recode(big.a) 7689.944 8123.826 8622.3087 8295.475 8583.322 14963.013 100 b 
atomic.ifelse(big.a) 21804.622 23092.946 24446.9123 24041.193 25475.073 29158.469 100 c 

(где f.match <- function(x) match(x,elements))

+0

Ах просто добавили его в мой тест - я не видел, что вы добавили его здесь. – josliber

+0

Спасибо за это, @ josilber - всегда приятно видеть, что результаты воспроизводимы –