2017-07-26 91 views
1

我一直在尋找相當長一段時間,但它似乎答案似乎總是使用eval(parse(text="1+1"))如何計算「1 + 1」不使用eval(解析(......?

我有一列在我的數據框中,它有一個字符串列表,例如「1 + 1 * 6」,「1 * 4/3」等。我希望將這些字段計算爲新列,而不使用eval(parse(函數,因爲我期望這樣做它超過800萬行

它基本上是一個試圖回答這樣一個問題:鑑於數字1:9找到所有的解決方案,其中(A_B_C)/(D_E_F) = GHI,其中A:I是數字1:9(不重複)和日下劃線是四個運營商之一*, /, +,-,也沒有重複。

我創建了一個所有排列爲1:9的數據框,並且我爲每個排列都計算了四個運算符的排列組合。

require(gtools) 
x <- permutations(n = 9, r = 9, v = 1:9) 
y <- permutations(n = 4, r = 4, v = c("*", "/", "+", "-")) 

for(i in 1:nrow(x)){ 
    for(j in 1:nrow(y)){ 
    math <- paste("(", x[i,1], y[j,1], x[i,2],y[j,2], x[i,3],")", "/", "(", x[i,4] ,y[j,3], x[i,5] ,y[j,4], x[i,6],")") 
    equals <- eval(parse(text=math)) 
    sum <- as.numeric(paste0(x[i,7], x[i,8], x[i,9])) 
    if(sum==equals) { 
     print(c(i,j)) 
    } 
    } 
} 

但是這需要的時間太長了,所以我試圖消除消費eval(parse(..

任何幫助的時間將非常感激。謝謝!

房地美

+0

請更新您的問題,使其更易於閱讀。 –

+0

將所有數字保留在9列中,然後使用類似「+(2,3)」的方式播放。無法正確格式化,用backtics包裝+符號。 – zx8754

+0

我同意@ zx8754,當你構造你的字符串時,你基本上是解析。避免這種情況,無需解析。如果你需要更多的幫助,你應該創建一個更小的例子。運行你的代碼需要很長時間。 – Roland

回答

1

矢量化是關鍵

math <- apply(
    y, 
    1, 
    function(j){ 
    paste("(", x[, 1], j[1], x[, 2], j[2], x[, 3],")/(", x[, 4], j[3], x[, 5], j[4], x[, 6], ")") 
    } 
) 
math <- apply(math, 2, paste, collapse = ",") 
math <- paste("c(", math, ")") 
equals <- sapply(parse(text = math), eval) 
sum <-matrix(x[, 7] * 100 + x[, 8] * 10 + x[, 9], nrow = nrow(x), ncol = nrow(y)) 
abs(sum - equals) < 1e-8 

讓我們來看看在速度上的差異是什麼

要求(gtools) X < - 排列(N = 9,R = 9,V = 1:9) y < - 置換(n = 4,r = 4,v = c(「*」,「/」,「+」,「 - 」))

x <- x[sample(nrow(x), 40), ] 
y <- y[sample(nrow(y), 20), ] 

library(microbenchmark) 
microbenchmark(
    loop = for(i in 1:nrow(x)){ 
    for(j in 1:nrow(y)){ 
     math <- paste("(", x[i,1], y[j,1], x[i,2],y[j,2], x[i,3],")", "/", "(", x[i,4] ,y[j,3], x[i,5] ,y[j,4], x[i,6],")") 
     equals <- eval(parse(text=math)) 
     sum <- as.numeric(paste0(x[i,7], x[i,8], x[i,9])) 
     if(sum==equals) { 
     print(c(i,j)) 
     } 
    } 
    }, 
    vectorised = { 
    math <- apply(
     y, 
     1, 
     function(j){ 
     paste("(", x[, 1], j[1], x[, 2], j[2], x[, 3],")/(", x[, 4], j[3], x[, 5], j[4], x[, 6], ")") 
     } 
    ) 
    math <- apply(math, 2, paste, collapse = ",") 
    math <- paste("c(", math, ")") 
    equals <- sapply(parse(text = math), eval) 
    sum <-matrix(x[, 7] * 100 + x[, 8] * 10 + x[, 9], nrow = nrow(x), ncol = nrow(y)) 
    abs(sum - equals) < 1e-8 
    } 
) 

結果:

Unit: milliseconds 
     expr  min   lq  mean  median   uq  max neval cld 
     loop 158.666383 162.084918 167.477490 165.880665 170.258076 240.43746 100 b 
vectorised 8.540623 8.966214 9.613615 9.142515 9.413117 17.88282 100 a 
+0

嗨蒂埃裏,謝謝你的評論。我試着運行你的向量化代碼'equals < - sapply(parse(text = math),eval)'但是我得到了錯誤'解析錯誤(文本=數學):負向長度向量不允許' - 不完全確定原因。謝謝! –