2016-09-26 76 views
0

我試圖用一組簡單的代碼替換多個單獨的Mapply語句。我終於得到它與3嵌套mapply聲明,但似乎有點複雜的方法。我是來自其他語言的新手,所以在R心態尋找一些幫助來思考。如果這三個陳述是最好的方法,我可以接受它,但要尋找輸入。如果你有更好的方法來構造像這樣的子集化輸出,那麼我就是耳朵。簡化嵌套Mapply語句

payments <- data.frame(
    Amount = sample(5:15,100,replace=TRUE), 
    Tip.Amount = round(runif(100,0,2),2), 
    "A" = sample(c(TRUE,FALSE),100,replace=TRUE), 
    "B" = sample(c(TRUE,FALSE),100,replace=TRUE), 
    "C" = sample(c(TRUE,FALSE),100,replace=TRUE), 
    "D" = sample(c(TRUE,FALSE),100,replace=TRUE), 
    "E" = sample(c(TRUE,FALSE),100,replace=TRUE), 
    "F" = sample(c(TRUE,FALSE),100,replace=TRUE), 
    Date = sample(seq(as.Date("2016-01-01"),as.Date("2016-01-31"),by="day"),100,replace=TRUE) 
) 
employees <- c("A","B","C","D","E","F") 
dots <- lapply(c(employees,"Date"),as.symbol) 

payments.by_date_employee <- payments %>% 
    filter(!is.na(Date),!is.na(Amount)) %>% 
    group_by_(.dots=dots) %>% 
    summarise(Payment.Count=n(), Amount=sum(Amount), 
      Tip.Count=sum(Tip.Amount>=0.01,na.rm=TRUE), Tip.Amount=sum(Tip.Amount,na.rm=TRUE)) %>% 
    ungroup() %>% 
    arrange(Date) 

#long/manual way-------------------------------------------------------------------------------- 
t <- list() 
t[["payments"]][["amount"]] <- mapply(function(name) list({ 
    t.test(subset(payments,payments[[name]]==TRUE)$Amount, 
     subset(payments,payments[[name]]==FALSE)$Amount)$p.value 
}), 
employees) 

t[["payments"]][["count"]] <- mapply(function(name) list({ 
    t.test(subset(payments.by_date_employee,payments.by_date_employee[[name]]==TRUE)$Amount, 
     subset(payments.by_date_employee,payments.by_date_employee[[name]]==FALSE)$Amount)$p.value 
}), 
employees) 

t[["tips"]][["amount"]] <- mapply(function(name) list({ 
    t.test(subset(payments,payments[[name]]==TRUE)$Tip.Amount, 
     subset(payments,payments[[name]]==FALSE)$Tip.Amount)$p.value 
}), 
employees) 

t[["tips"]][["count"]] <- mapply(function(name) list({ 
    t.test(subset(payments.by_date_employee,payments.by_date_employee[[name]]==TRUE)$Tip.Amount, 
     subset(payments.by_date_employee,payments.by_date_employee[[name]]==FALSE)$Tip.Amount)$p.value 
}), 
employees) 
#long/manual way-------------------------------------------------------------------------------- 

#attempt at single mapply statement ------------------------------------------------------------ 
y <- mapply(function(name,type,variable,df,nm) list({ 
    t.test(subset(eval(df),eval(df)[[name]]==TRUE)[[nm]], 
     subset(eval(df),eval(df)[[name]]==FALSE)[[nm]])$p.value}), 
    employees, 
    c("payments","payments","tips","tips"), 
    c("amount","count"), 
    c(quote(payments),quote(payments),quote(payments.by_date_employee),quote(payments.by_date_employee)), 
    c("Amount","Amount","Tip.Amount","Tip.Amount"), 
    SIMPLIFY = FALSE 
) 
#attempt at single mapply statement ------------------------------------------------------------ 

#works but seems convoluted -------------------------------------------------------------------- 
z <- mapply(function(type) list({ 
    mapply(function(variable,df,nm) list({ 
    t[[type]][[variable]] <-mapply(function(name) list({ 
     t.test(subset(eval(df),eval(df)[[name]]==TRUE)[[nm]], 
      subset(eval(df),eval(df)[[name]]==FALSE)[[nm]])$p.value}), 
     employees) 
    }), 
    c("amount","count"), 
    c(quote(payments),quote(payments),quote(payments.by_date_employee),quote(payments.by_date_employee)), 
    c("Amount","Amount","Tip.Amount","Tip.Amount"), 
    SIMPLIFY = FALSE 
) 
}), 
c("payments","tips") 
) 
#works but seems convoluted -------------------------------------------------------------------- 

回答

1

下面是將問題分解爲幾個步驟的方法。首先,編寫一個函數,需要一個數據幀,一個變量名,和員工代碼的名稱,並返回所需的值:

ttest <- function(data, varname, employee) { 
    d <- get(data) 
    do.call(t.test, setNames(split(d[[varname]], d[[employee]]), c("x", "y")))$p.value 
} 

現在,使用mapply超過數據幀的名字向量應用函數,變量姓名和職員代碼:

out <- mapply(ttest, 
    rep(c("payments", "payments.by_date_employee"), each = length(employees)), 
    c(rep(c("Amount", "Tip.Amount"), each = length(employees) * 2)), 
    employees) 

現在,我們擁有所有我們需要的值。檢查值是相同的那些從你的列表t

all.equal(unname(out), unname(unlist(t))) 
# [1] TRUE 

剩下的步驟是組織的價值觀。我們可以把它們放入一個數據幀:

d <- data.frame(
    type = rep(c("payments", "tips"), each = length(employees) * 2), 
    variable = rep(c("amount", "count"), each = length(employees), times = 2), 
    employee = rep(employees, times = 4), 
    value = out 
) 
#  type variable employee  value 
# 1 payments amount  A 0.23278642 
# 2 payments amount  B 0.77047594 
# ... 
# 7 payments count  A 0.56123674 
# 8 payments count  B 0.81040604 
# ... 
# 13  tips amount  A 0.92749503 
# 14  tips amount  B 0.08716570 
# ... 
# 23  tips count  E 0.20672583 
# 24  tips count  F 0.23505606 

一個步驟,如果你想你的結果作爲嵌套列表:

y <- lapply(split(d, d$type), 
    function(x) lapply(split(x, x$variable), 
    function(y) split(y$value, y$employee) 
) 
) 
all.equal(t, y) 
# [1] TRUE 

更新。要從t.test輸出獲得額外的價值,首先修改我們的自定義ttest功能

ttest <- function(data, varname, employee) { 
    d <- get(data) 
    unlist(
    do.call(t.test, setNames(split(d[[varname]], d[[employee]]), c("x", "y")))[c("estimate", "p.value")] 
) 
} 

其中在這種情況下,我們爲estimatep.value提取值(其它值的名稱,你可以檢查任何t.test輸出,如。str(t.test(1:3, 4:6))如上所述的unlist函數變平我們檢索(最初以列表的形式)的值到載體

運行mapply;目前,out對象是一個矩陣,而不是一個向量假設我們要將值插入一個數據框:

d <- data.frame(
    type = rep(c("payments", "tips"), each = length(employees) * 2), 
    variable = rep(c("amount", "count"), each = length(employees), times = 2), 
    employee = rep(employees, times = 4), 
    x.mean = out[1, ], 
    y.mean = out[2, ], 
    p.value = out[3, ] 
) 
     type variable employee x.mean y.mean p.value 
# 1 payments amount  A 10.217391 10.240741 0.9714363 
# 2 payments amount  B 9.960784 10.510204 0.4022349 
# 3 payments amount  C 10.490196 9.959184 0.4153361 
# . ...  ...   
+0

絕對看到它的工作原理。在標記爲正確之前嘗試理解你所做的事情。你正在做一些對我來說很陌生的事情! – atclaus

+0

您會如何建議從t檢驗中提取額外的值?我正在尋找x和y的意思,所以我可以總結出存在差異的方向...... – atclaus

+0

請參閱編輯。 –