[英]How to create new columns conditional of columns in a df and sum them together to one in R
我對 R 很陌生,並且有一個 df,我在其中使用 sqldf 創建了一些標准(a1、b1、c1、d1.. 等等)(在這個例子中,我只顯示 a1 到 c1)
df <- data.frame('var1' = c('x','1', 'X', '', 'X'), "var2" = c('y','3', '', 'X', ''), "var3" = c('y','7', '', 'X', 'X'))
library(sqldf)
testcases_sql <-
("
CASE WHEN var1 = 1 THEN 1 ELSE 0 END AS a1,
CASE WHEN var1 = 1 AND var2 = 'y' THEN 1 ELSE 0 END AS b1,
CASE WHEN var1= 1 AND var2= 3 THEN 1 ELSE 0 END AS b1,
CASE WHEN var1= 1 AND var2= 3 THEN 1 ELSE 0 END AS b1,
CASE WHEN var1= 1 AND var2= 'X' THEN 1 ELSE 0 END AS b1,
CASE WHEN var1= 1 AND var2= 'X' AND var3=7 THEN 1 ELSE 0 END AS c1,
CASE WHEN var1= 'X' AND var3='X' THEN 1 ELSE 0 END AS c1")
sql_string = paste("SELECT *" , ",", testcases_sql, " FROM ", "df", sep=" ")
#create criteria
data = sqldf(sql_string)
head(data)
SQLDF 為每個條件創建一個新列
head(data)
# var1 var2 var3 a1 b1 b1 b1 b1 c1 c1
# 1 x y y 0 0 0 0 0 0 0
# 2 1 3 7 1 0 1 1 0 0 0
# 3 X 0 0 0 0 0 0 0
# 4 X X 0 0 0 0 0 0 0
# 5 X X 0 0 0 0 0 0 1
但是我需要一個變量中的所有標准,以便所有 b1 都在一個列中,所有 c1 都在一個列中,依此類推。 每行符合標准多少次都沒關系,我只需要每列中的“1”。 在我原來的 df 中,沒有一個標准可以重復多少次的系統,它完全是隨機的。
我的預期結果是:
wished_df <- data.frame('var1' = c('x','1', 'X', '', 'X'), "var2" = c('y','3', '', 'X', ''), "var3" = c('y','7', '', 'X', 'X'), "a1" = c('0','1', '0', '0', '0'), "b1=" =c('0','1', '0', '0','0'), "c1=" =c('0','0', '0', '0','1') )
head(wished_df)
# var1 var2 var3 a1 b1 c1
#1 x y y 0 0 0
#2 1 3 7 1 1 0
#3 X 0 0 0
#4 X X 0 0 0
#5 X X 0 0 1
這可能是 sqldf 不是最好的 function 。 我最好的方法是通過將變量相加來更改 df
#sum the variable
data$newb1 <- data$b1 + data$b1 + data$b1 + data$b1
#error in `$<-.data.frame`(`*tmp*`, newb1, value = numeric(0)) : replacement has 0 rows, data has 5
#delete the old variable
data$b1 <- data$b1 <-data$b1 <- data$b1 <- NULL
#rename the variable
data$b1 <- data$newb1
#delete old variable
data$newb1 <- NULL
#repeat for c1, d1, e1 and so on...
data$newc1 <- data$c1 + data$c1
data$c1 <- data$c1 <- NULL
data$c1 <- data$newc1
data$newc1 <- NULL
這不起作用,而且非常難看,需要大量代碼(我有 80 個測試用例)。
有沒有更簡單的方法來做到這一點?
非常感謝提前
我將只使用 R 的內置 boolean 運算符來完成此任務。 注意我已經從您的 SQL 選擇中刪除了一些邏輯冗余:
df <- data.frame('var1' = c('x','1', 'X', '', 'X'),
"var2" = c('y','3', '', 'X', ''),
"var3" = c('y','7', '', 'X', 'X'))
df$a1 <- 1 * (df$var1 == "1")
df$b1 <- 1 * ((df$var1 == "1") & (df$var2 == "y" | df$var2 == "3" | df$var2 == "X"))
df$c1 <- 1 * ((df$var1 == "1" & df$var2 == "X" & df$var3 == "7") |
(df$var1 == "X" & df$var3 == "X"))
df
#> var1 var2 var3 a1 b1 c1
#> 1 x y y 0 0 0
#> 2 1 3 7 1 1 0
#> 3 X 0 0 0
#> 4 X X 0 0 0
#> 5 X X 0 0 1
由代表 package (v0.3.0) 於 2020 年 5 月 14 日創建
在 SQL 我們可以 OR 條件來簡化代碼。 每個 true 條件將評估為 1,每個 false 條件評估為 0。我們已將 SQL 字符串的名稱更改為testcasesSQL
,因為 $ 字符串插值需要單詞字符作為變量名 -- 非單詞字符終止變量名並且不被視為作為變量名的一部分。
如果測試用例有一些模式,那么我們可以使用 R 代碼生成 testcasesSQL 字符串,但不清楚是否存在,我們只是修復問題中的代碼並將其轉換為更緊湊的 SQL。
請注意,邏輯條件 (var1 = 1) 或 (var1 = 1 AND var2 = 'y') 可以簡化為 (var1 = 1)。 下面我們沒有應用這個或其他潛在的邏輯簡化來明確問題中的代碼如何直接轉換為更簡單的 SQL。 此外,如果這些是自動生成的,它可能無論如何都不是最簡單的形式,從答案的角度來看,它沒有區別。
library(sqldf)
testcasesSQL <- "(var1 = 1) or (var1 = 1 AND var2 = 'y') as a1,
(var1 = 1 AND var2 = 'y') or (var1 = 1 AND var2 = 3) or (var1 = 1 AND var2 = 'X') AS b1,
(var1 = 1 AND var2 = 'X' AND var3 = 7) or (var1 = 'X' AND var3 ='X') AS c1"
dfname <- "df"
fn$sqldf("select *, $testcasesSQL from $dfname")
給予:
var1 var2 var3 a1 b1 c1
1 x y y 0 0 0
2 1 3 7 1 1 0
3 X 0 0 0
4 X X 0 0 0
5 X X 0 0 1
我們可以定義一個矩陣,其條件名稱為第 1 列,其中一列用於 var1、var2 和 var3,這樣一行上的條件是 AND'd,而多行上的條件具有相同的條件名稱 OR'd。 從問題中的示例看來, var1 似乎始終存在,我們在gsub
行中使用了該事實。
condmat <- matrix(c('c1', 1, NA, NA,
'c1', 1, 'y', NA,
'c2', 1, 'y', NA,
'c2', 1, 3, NA,
'c2', 1, 'X', NA,
'c3', 1, 'X', 7,
'c3', 'X', NA, 'X'),, 4, byrow = TRUE)
colnames(condmat) <- c("cond", "var1", "var2", "var3")
s <- sprintf("(%s = '%s' AND %s = '%s' AND %s = '%s')",
colnames(condmat)[2], condmat[, 2],
colnames(condmat)[3], condmat[, 3],
colnames(condmat)[4], condmat[, 4])
s2 <- gsub("AND \\w+ = 'NA'", "", s)
s3 <- tapply(s2, condmat[, 1], paste, collapse = " OR ")
cond <- paste(paste(s3, 'as', names(s3)), collapse = ",\n")
dfname <- "df"
fn$sqldf("select *, $cond from $dfname")
請注意,上面生成的 cond 變量是:
cat(cond)
## (var1 = '1' ) OR (var1 = '1' AND var2 = 'y' ) as c1,
## (var1 = '1' AND var2 = 'y' ) OR (var1 = '1' AND var2 = '3' ) OR (var1 = '1' AND var2 = 'X' ) as c2,
## (var1 = '1' AND var2 = 'X' AND var3 = '7') OR (var1 = 'X' AND var3 = 'X') as c3
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.