2015-11-09 137 views
0

我需要遍歷數據框並計算正在循環的變量的函數。循環變量的R-ddply函數

的表例如:

table<-data.frame(num1=seq(1,10,len=20), num2=seq(20,30,len=20), 
    char1=c(rep('a',10), rep('b',10)), 
    target=c(rep(1,10), rep(0,10))) 

我創建的變量列表:

nums<-colnames(table)[sapply(table, class)=='numeric'] 
nums<-nums[nums!='target'] 

而且表,我將填充:

planF<-data.frame(deciles=c(1), min=c(1), max=c(1), pos=c(1)) 
planF<-planF[-1,] 

,循環:

library(plyr) 

for (i in 1:length(nums)){ 
table$deciles<-ntile(table[,nums[i]],5) 
plan<-ddply(table, 'deciles', summarize, min=min(nums[i]), 
     max=max(nums[i]),pos=sum(target)) 
planF<-rbind(planF,plan) 
} 

我需要獲取每個十分位變量por的最小值和最大值。而是我得到:

deciles min max pos 
1  1 num1 num1 4 
2  2 num2 num2 4 
3  3 <NA> <NA> 2 
4  4 <NA> <NA> 0 
5  5 <NA> <NA> 0 
6  1 num1 num1 4 
7  2 num2 num2 4 
8  3 <NA> <NA> 2 
9  4 <NA> <NA> 0 
10  5 <NA> <NA> 0 

對於可變NUM1我需要得到的結果是:

ddply(table, 'deciles', summarize, min=min(num1), 
     max=max(num1),pos=sum(target)) 


    deciles  min  max pos 
     1 5.736842 7.157895 0 
     2 7.631579 9.052632 0 
     3 1.000000 10.000000 2 
     4 1.947368 3.368421 4 
     5 3.842105 5.263158 4 

而且做同樣與NUM2的結果如下。

我明白,我需要引入具有下列形式的變量:

num1

但代碼編寫

'num1'

我試着用:

min=min(as.name(nums[i])) 

但我出現錯誤:

Error in min(as.name(nums[i])) : 'type' (symbol) not valid argument

我該如何計算一個正在循環變量的函數?

+0

很難確定你正在嘗試做什麼。你能用文字解釋嗎? – MJeffryes

+0

@MJeffryes:嗨,我需要獲得變量por的最小值和最大值。 – GabyLP

+0

如果你也會顯示你想要的輸出,會更容易。 –

回答

0

我將嚴格喜歡使用dplyr這一點,即使是在調用summarize_處理字符串變量名的一些醜陋(注意尾隨_):

library(lazyeval) 
library(dplyr) 

# create the data.frame 
dfX = data.frame(num1=seq(1,10,len=20), 
       num2=seq(20,30,len=20), 
       char1=c(rep('a',10), rep('b',10)), 
       target=c(rep(1,10), rep(0,10)) 
) 

# select the numeric columns 
numericCols = names(dfX)[sapply(dfX, is.numeric)] 
numericCols = setdiff(numericCols, "target") 

# cycle over numeric columns, creating summary data.frames 
liDFY = setNames(
    lapply(
    numericCols, function(x) { 
     # compute the quantiles 
     quantiles = quantile(dfX[[x]], probs = seq(0, 1, 0.2)) 

     # create quantile membership 
     dfX[["quantile_membership"]] = 
     findInterval(dfX[[x]], vec = quantiles, 
        rightmost.closed = TRUE, 
        all.inside = TRUE) 

     # summarize variables by decile 
     dfX %>% 
     group_by(quantile_membership) %>% 
     summarize_(min = interp(~ min(x_name), x_name = as.name(x)), 
        max = interp(~ max(x_name), x_name = as.name(x)), 
        mean = interp(~ mean(x_name), x_name = as.name(x))) 
    }), 
    numericCols 
) 

# inspect the output 
liDFY[[numericCols[1]]] 
+0

謝謝! 2個問題:findInterval做什麼?以及如何引入變量名稱(每行)以知道哪些變量編號屬於? – GabyLP

+0

@GabyLP'findInterval'使用上面一行計算的分位數來存儲每個觀察值(無論是在第一個分位數,第二個分位數等),以便我們可以使用該信息對數據進行分組並計算最小值,最大和其他彙總統計。 – tchakravarty

+1

@GabyLP你可以簡單地添加'%>%mutate(varname = x)'。 – tchakravarty

1

你的問題的要點是要在split-apply-combine方法上應用函數列表,所以這裏有一種方法可以在base r中執行此操作。

## your data 
table<-data.frame(num1=seq(1,10,len=20), num2=seq(20,30,len=20), 
        char1=c(rep('a',10), rep('b',10)), 
        target=c(rep(1,10), rep(0,10))) 
nums<-colnames(table)[sapply(table, class)=='numeric'] 
nums<-nums[nums!='target'] 
table$deciles <- ntile(table[, nums[1]], 5) 

FUNS <- list(min = min, max = max, mean = mean) 

## split the variable num1 by deciles 
## apply each function to each piece 
x <- with(table, tapply(num1, deciles, function(x) 
    setNames(sapply(FUNS, function(y) y(x)), names(FUNS)))) 

## combine results 
do.call('rbind', x) 
#  min  max  mean 
# 1 1.000000 2.421053 1.710526 
# 2 2.894737 4.315789 3.605263 
# 3 4.789474 6.210526 5.500000 
# 4 6.684211 8.105263 7.394737 
# 5 8.578947 10.000000 9.289474 

而不是使用一個循環的,因爲我們有工作,是相當簡單的上面,把它變成一個功能類似下面

f <- function(num, data = table) { 
    FUNS <- list(min = min, max = max, mean = mean) 

    x <- tapply(data[, num], data[, 'deciles'], function(x) 
    setNames(sapply(FUNS, function(y) y(x)), names(FUNS))) 

    cbind(deciles = as.numeric(names(x)), do.call('rbind', x)) 
} 

通過這種方式,我們的方法推廣,因此可以使用您擁有任何數據的任何列。你可以把它單獨的列像

f('num1') 
f('num2') 

或者使用循環一次

lapply(c('num1','num2'), f) 

# [[1]] 
# deciles  min  max  mean 
# 1  1 1.000000 2.421053 1.710526 
# 2  2 2.894737 4.315789 3.605263 
# 3  3 4.789474 6.210526 5.500000 
# 4  4 6.684211 8.105263 7.394737 
# 5  5 8.578947 10.000000 9.289474 
# 
# [[2]] 
# deciles  min  max  mean 
# 1  1 20.00000 21.57895 20.78947 
# 2  2 22.10526 23.68421 22.89474 
# 3  3 24.21053 25.78947 25.00000 
# 4  4 26.31579 27.89474 27.10526 
# 5  5 28.42105 30.00000 29.21053 

得到的一切。如果你不喜歡lapply,你可以Vectorize功能,使其變得更輕鬆:

Vectorize(f, SIMPLIFY = FALSE)(c('num1', 'num2')) 

,你想這更普遍使用(SIMPLIFY = FALSE,保留列表結構)

v <- Vectorize(f, SIMPLIFY = FALSE) 
v(c('num1','num1')) 

# $num1 
# deciles  min  max  mean 
# 1  1 1.000000 2.421053 1.710526 
# 2  2 2.894737 4.315789 3.605263 
# 3  3 4.789474 6.210526 5.500000 
# 4  4 6.684211 8.105263 7.394737 
# 5  5 8.578947 10.000000 9.289474 
# 
# $num1 
# deciles  min  max  mean 
# 1  1 1.000000 2.421053 1.710526 
# 2  2 2.894737 4.315789 3.605263 
# 3  3 4.789474 6.210526 5.500000 
# 4  4 6.684211 8.105263 7.394737 
# 5  5 8.578947 10.000000 9.289474