2015-09-15 5 views
0

у меня есть кадры два данных следующим образом:Расчет результата формулы путем сопоставления числа

a1 <- data.frame(ID = c(1:4), type = c(463,479, 5357,4771), amount = c(110,95,2100,23)) 
a2 <- data.frame(AltID = c(101:103), Calculation = c('[479]+[4771]','[5357]/([479]*[463])','([463]-[4771])/[5357]')) 

> str(a1) 
'data.frame': 4 obs. of 3 variables: 
$ ID : int 1 2 3 4 
$ type : num 463 479 5357 4771 
$ amount: num 110 95 2100 23 

> str(a2) 
'data.frame': 3 obs. of 2 variables: 
$ AltID  : int 101 102 103 
$ Calculation: Factor w/ 3 levels "([463]-[4771])/[5357]",..: 2 3 1 

Цифры в «скобке», которые появляются в столбце «Расчет» в «а2» все имеющиеся в столбец «тип» в «a1», который имеет соответствующее значение в столбце «сумма» в «a1».

Цель состоит в том, чтобы добавить столбец в «a2», который использует формулу «Расчет» в каждой строке «a2», сопоставлять числа с типом a1 $ и использовать правильные арифметические операции для создания одного числа, которое соответствует каждой строке «AltID» в «a2».

Для приведенного выше примера,

a2$result <- rep(0,3) 

, и я хотел бы получить:

a2$result[1] = 95+23 
a2$result[2] = 2100/(95*110) 
a2$result[3] = (110-23)/2100 

мне было интересно, если есть умный способ сделать это.

Спасибо заранее

ответ

2

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

Вот как я бы идти о вашей проблеме, как указано:

Сначала я собираюсь заменить type номера в a1 с действительными именами переменных, вставив x на передней панели. Тогда я придерживаюсь их в своей среде, так что мы можем использовать эти переменные позже, не загромождая рабочее пространство:

a1$var = paste0("x", a1$type) # make variable names 
a1_env = new.env()   # create new environment 
           # fill new environment: 
mapply(FUN = assign, x = a1$var, value = a1$amount, MoreArgs = list(envir = a1_env)) 

Теперь мы собираемся заменить скобки чисел в a2 с одинаковыми именами переменных. Это означает, что мы удаляем близкие скобки ] и заменить открытые кронштейны с "x", чтобы соответствовать имена переменных, созданных в a1_env:

a2$Calculation = gsub(pattern = "\\[", replacement = "x", x = a2$Calculation) 
a2$Calculation = gsub(pattern = "\\]", replacement = "", x = a2$Calculation) 

a2 
# AltID  Calculation 
# 1 101   x479+x4771 
# 2 102 x5357/(x479*x463) 
# 3 103 (x463-x4771)/x5357 

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

a2$Result = sapply(a2$Calculation, FUN = function(x) { 
    eval(parse(text = x), envir = a1_env) 
}) 

a2 
# AltID  Calculation  Result 
# 1 101   x479+x4771 118.00000000 
# 2 102 x5357/(x479*x463) 0.20095694 
# 3 103 (x463-x4771)/x5357 0.04142857 

Этот ответ приходит с обязательным предупреждением:

> fortunes::fortune(106) 
If the answer is parse() you should usually rethink the question. 
    -- Thomas Lumley 
     R-help (February 2005) 
+0

Очень умное решение. –

2
library(stringr) 
for(i in 1:nrow(a1)) { 
    a2$Calculation <- str_replace_all(a2$Calculation, as.character(a1$type[i]), as.character(a1$amount[i]))} 
a2$Calculation <- gsub("\\[|\\]", "", a2$Calculation) 
a2$Total <- sapply(a2$Calculation, function(x) eval(parse(text=x))) 
a2 
# AltID Calculation  Total 
#1 101   95+23 118.00000000 
#2 102 2100/(95*110) 0.20095694 
#3 103 (110-23)/2100 0.04142857 

В этом случае цикл for работает, потому что он сохраняет последнюю замену и использует ее для следующей итерации. Мы заменяем каждое значение шаг за шагом на str_replace_all. Затем мы удаляем скобки с помощью gsub. И, наконец, мы используем eval(parse(text=x)) для перехода от текстовой строки операций к фактическим значениям.

Следуйте общей осторожности Gregor в отношении разбора текста. Обычно, когда кто-то нуждается в ней для вызова функции, где-то в конвейере, они закрепили себя в углу программирования, которого можно было бы избежать.

Смежные вопросы