2017-07-02 80 views
2

我正在尋找一種操作數據框內多個變量的有效方法。現在我正在使用dplyr,但是這對於更多的變量來說很麻煩。 假設我有以下數據框,其中brd是汽車品牌,ye是一年,type是汽車類型,cy和hp是類型特徵。在一個循環中總結並生成多個變量

brd <-c("BMW","BMW","BMW","Volvo","Volvo", "Volvo","BMW","BMW","BMW","Volvo","Volvo","Volvo") 
ye <- c(99,99,99,99,99,99,98,98,98,98,98,98) 
type <- c(1,2,3,1,2,3,1,2,3,1,2,3) 
cy <- c(1895,1991,1587,2435,2435,1596,1991,1588,1984,1596,1991,1588) 
hp <- c(77,110,80,103,103,75,110,77,93,75,110,77) 

df <- as.data.frame(brd) 
df$ye <- ye 
df$type <- type 
df$cy <- cy 
df$hp <- hp  
df 
    brd ye type cy hp 
1 BMW 99 1 1895 77 
2 BMW 99 2 1991 110 
3 BMW 99 3 1587 80 
4 Volvo 99 1 2435 103 
5 Volvo 99 2 2435 103 
6 Volvo 99 3 1596 75 
7 BMW 98 1 1991 110 
8 BMW 98 2 1588 77 
9 BMW 98 3 1984 93 
10 Volvo 98 1 1596 75 
11 Volvo 98 2 1991 110 
12 Volvo 98 3 1588 77 

每一年,我想計算的產品特性的總和同一品牌的其他所有產品,並將其添加爲新的變量數據框。現在,我使用dplyr這樣的:

library(dplyr) 
df <- df %>% group_by(brd, ye) %>% 
    mutate(sumall_cy = sum(cy), 
     sumall_hp = sum(hp)) 

df <- df %>% 
    mutate(sumother_cy = sumall_cy-cy, 
     sumother_hp = sumall_li-hp) 

所以,我得到

 brd ye type cy hp sumall_cy sumall_hp sumother_cy sumother_hp 
    <fctr> <dbl> <dbl> <dbl> <dbl>  <dbl>  <dbl>  <dbl>  <dbl> 
1  BMW 99  1 1895 77  5473  267  3578   190 
2  BMW 99  2 1991 110  5473  267  3482   157 
3  BMW 99  3 1587 80  5473  267  3886   187 
4 Volvo 99  1 2435 103  6466  281  4031   178 
5 Volvo 99  2 2435 103  6466  281  4031   178 
6 Volvo 99  3 1596 75  6466  281  4870   206 
7  BMW 98  1 1991 110  5563  280  3572   170 
8  BMW 98  2 1588 77  5563  280  3975   203 
9  BMW 98  3 1984 93  5563  280  3579   187 
10 Volvo 98  1 1596 75  5175  262  3579   187 
11 Volvo 98  2 1991 110  5175  262  3184   152 
12 Volvo 98  3 1588 77  5175  262  3587   185 

有沒有更有效的方法?我正在考慮像這個stata代碼循環:

foreach x of varlist hp cy { 

bysort ye: egen sumall_`x'= sum(`x') 
gen sumother_`x'=(sumall_`x' -`x')} 

任何意見將不勝感激。

+0

您可以在以'df'開頭的管道中調用'left_join'(例如'left_join(。,summarize())'來生成組級摘要,然後像你一樣進行mutate'這裏。它不會做更少的工作,但所有的工作都在同一個管道內,如果你關心的話。 – ulfelder

回答

1

這裏是non-standard evaluation的解決方案,該group_by操作只需進行一次完成,也適用,當你有更多的列的過程:

library(dplyr) # 0.7.0 
library(rlang) # required for the `syms` function 

varlist <- c('cy', 'hp') 

# make a list of quos of opertions 
ops <- sapply(syms(varlist), function(x) quo(sum(UQ(x)) - UQ(x))) 

# set new variable name 
names(ops) <- paste('sumother', varlist, sep = '_') 

# get results 
df %>% group_by(brd, ye) %>% mutate(!!!ops) %>% ungroup() 
# # A tibble: 12 x 7 
#  brd ye type cy hp sumother_cy sumother_hp 
# <fctr> <dbl> <dbl> <dbl> <dbl>  <dbl>  <dbl> 
# 1 BMW 99  1 1895 77  3578   190 
# 2 BMW 99  2 1991 110  3482   157 
# 3 BMW 99  3 1587 80  3886   187 
# 4 Volvo 99  1 2435 103  4031   178 
# 5 Volvo 99  2 2435 103  4031   178 
# 6 Volvo 99  3 1596 75  4870   206 
# 7 BMW 98  1 1991 110  3572   170 
# 8 BMW 98  2 1588 77  3975   203 
# 9 BMW 98  3 1984 93  3579   187 
# 10 Volvo 98  1 1596 75  3579   187 
# 11 Volvo 98  2 1991 110  3184   152 
# 12 Volvo 98  3 1588 77  3587   185 

如果我們想保持sumall_列,我們可以嘗試:

ops <- sapply(syms(varlist), function(x) list(quo(sum(UQ(x))), quo(sum(UQ(x)) - UQ(x)))) 
names(ops) <- paste(
    rep(c('sumall', 'sumother'), length(varlist)), 
    rep(varlist, each = 2), sep = '_') 
df %>% group_by(brd, ye) %>% mutate(!!!ops) %>% ungroup() 

# # A tibble: 12 x 9 
#  brd ye type cy hp sumall_cy sumother_cy sumall_hp sumother_hp 
# <fctr> <dbl> <dbl> <dbl> <dbl>  <dbl>  <dbl>  <dbl>  <dbl> 
# 1 BMW 99  1 1895 77  5473  3578  267   190 
# 2 BMW 99  2 1991 110  5473  3482  267   157 
# 3 BMW 99  3 1587 80  5473  3886  267   187 
# 4 Volvo 99  1 2435 103  6466  4031  281   178 
# 5 Volvo 99  2 2435 103  6466  4031  281   178 
# 6 Volvo 99  3 1596 75  6466  4870  281   206 
# 7 BMW 98  1 1991 110  5563  3572  280   170 
# 8 BMW 98  2 1588 77  5563  3975  280   203 
# 9 BMW 98  3 1984 93  5563  3579  280   187 
# 10 Volvo 98  1 1596 75  5175  3579  262   187 
# 11 Volvo 98  2 1991 110  5175  3184  262   152 
# 12 Volvo 98  3 1588 77  5175  3587  262   185 
+0

@UweBlock,當然。我做了一個編輯。 – mt1022

+0

謝謝,現在看起來更像OP給出的例子。 – Uwe

+0

我原來以爲OP根據OP的描述只想要somother_。無論如何,做出改變並不難。 – mt1022

1

如果有很多類型的特徵,如cyhp,我建議將數據重塑長格式,並完成所有的類似的轉變那裏。爲了這個目的,melt()dcast()data.table包被使用:

library(data.table) # CRAN version 1.10.4 used 
# coerce to data.table 
DT <- data.table(df) 
# reshape from wide to long format, 
# specify id.vars because number of measure.vars may change in the future 
long <- melt(DT, id.vars = c("brd", "ye", "type")) 
# create additional columns 
long[, sumall := sum(value), by = .(brd, ye, variable)][, sumother := sumall - value][] 
# reshape from long to wide format 
dcast(long, brd + ye + type ~ ..., value.var = c("value", "sumall", "sumother")) 
 brd ye type value_cy value_hp sumall_cy sumall_hp sumother_cy sumother_hp 
1: BMW 98 1  1991  110  5563  280  3572   170 
2: BMW 98 2  1588  77  5563  280  3975   203 
3: BMW 98 3  1984  93  5563  280  3579   187 
4: BMW 99 1  1895  77  5473  267  3578   190 
5: BMW 99 2  1991  110  5473  267  3482   157 
6: BMW 99 3  1587  80  5473  267  3886   187 
7: Volvo 98 1  1596  75  5175  262  3579   187 
8: Volvo 98 2  1991  110  5175  262  3184   152 
9: Volvo 98 3  1588  77  5175  262  3587   185 
10: Volvo 99 1  2435  103  6466  281  4031   178 
11: Volvo 99 2  2435  103  6466  281  4031   178 
12: Volvo 99 3  1596  75  6466  281  4870   206 

在情況下,sumall列未在最終結果所需的,它們可以在重塑之前移除:

dcast(long[, sumall := NULL], brd + ye + type ~ ..., value.var = c("value", "sumother")) 
 brd ye type value_cy value_hp sumother_cy sumother_hp 
1: BMW 98 1  1991  110  3572   170 
2: BMW 98 2  1588  77  3975   203 
3: BMW 98 3  1984  93  3579   187 
4: BMW 99 1  1895  77  3578   190 
5: BMW 99 2  1991  110  3482   157 
6: BMW 99 3  1587  80  3886   187 
7: Volvo 98 1  1596  75  3579   187 
8: Volvo 98 2  1991  110  3184   152 
9: Volvo 98 3  1588  77  3587   185 
10: Volvo 99 1  2435  103  4031   178 
11: Volvo 99 2  2435  103  4031   178 
12: Volvo 99 3  1596  75  4870   206 
+0

完美,謝謝。我認爲這是滿足我的要求的一個很好的解決方案。 – Franzi