2017-06-03 201 views
1

**的樣本數據**如何從長重塑數據評論後加入寬

我有什麼:

pmts <- data.frame(stringsAsFactors=FALSE, 
      name = c("johndoe", "johndoe", "janedoe", "foo", "foo", "foo"), 
      pmt_amount = c(550L, 550L, 995L, 375L, 375L, 375L), 
      pmt_date = c("9/1/16", "11/1/16", "12/15/16", "1/5/17", "3/5/17", "5/5/17") 
) 

#>  name pmt_amount pmt_date 
#> 1 johndoe  550 9/1/16 
#> 2 johndoe  550 11/1/16 
#> 3 janedoe  995 12/15/16 
#> 4  foo  375 1/5/17 
#> 5  foo  375 3/5/17 
#> 6  foo  375 5/5/17 

我尋找實現:

read.table(header = T, text = 
"name pmt_amount first_pmt second_pmt third_pmt 
johndoe 550  9/1/16  11/1/16 NA 
    janedoe 995  12/15/16  NA  NA 
    foo  375  1/5/17  3/5/17 5/5/17" 
) 

#>  name pmt_amount first_pmt second_pmt third_pmt 
#> 1 johndoe  550 9/1/16 11/1/16  <NA> 
#> 2 janedoe  995 12/15/16  <NA>  <NA> 
#> 3  foo  375 1/5/17  3/5/17 5/5/17 

**更新結束**

我有一個包含不同產品付款信息的大型數據集。其中一些產品具有全額付款選項以及兩付和三付的選項。我需要創建將是First_Payment,Second_Payment和Third_Payment的字段,並且如果只有一個或兩個付款,則會在各個字段中填充NA。

我試過一對夫婦的選擇和最好的解決方法我到目前爲止是這樣的:

pmts %>% 
    group_by(Email, Name, Amount, Form.Title) %>% 
    summarise(First_Payment = min(Payment.Date), 
      Second_Payment = median(Payment.Date), 
      Last_Payment = max(Payment.Date)) -> pmts 

這顯然是不理想的,因爲正在彌補付款日期爲2,薪酬計劃,我會必須指示最終用戶忽略此字段,並只查看第1和第3字段。

我也試圖與部分種這樣的總結:

n <- length(pmts$Payment.Date) 
sort(pmts$Payment.Date,partial=n-1)[n-1] 

但是,如果有不適合的人三次付款,則需N-1日期從整個數據集和應用到所有其他領域。

理想情況下,我要這樣,如果它是一個付費的,充滿了付息領域將有日期和第二/第三場會說NA。 2工資將有第一和第二日期,第三場將表示不適用。最後3個薪水將有3個日期。

這裏的最終用戶是不是超級數據悟性,所以我試圖讓這個一樣容易地解釋。任何建議將非常感激。謝謝!

+4

你需要[做你的榜樣重複性]通過增加樣本數據(http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example#5963610)。 – alistaire

回答

1

使用data.table這是一個簡單的一行

library(data.table) #v1.9.8+ 
dcast(setDT(pmts), name + pmt_amount ~ rowid(pmt_amount)) 
# Using 'pmt_date' as value column. Use 'value.var' to override 
#  name pmt_amount  1  2  3 
# 1:  foo  375 1/5/17 3/5/17 5/5/17 
# 2: janedoe  995 12/15/16  NA  NA 
# 3: johndoe  550 9/1/16 11/1/16  NA 

dcast從長轉換成寬和它接受表達式。 rowid只是增加一個行計數器每pmt_amount

+0

謝謝!我試圖使用這個,但是當我完全按照它的樣子重現代碼時 - 它給了我一個2,028個變量的數據框,而不是你的例子中產生的5個變量。任何想法可能發生在這裏? > dcast(setDT(pmts),Email + Amount〜rowid(Amount)) - > pmts2 使用Payment.Date作爲值列:使用value.var來覆蓋。 –

+0

@JamesSnay它爲您提供了大量的變量,因爲您在某個'name' /'pmt_amount'組合中有更多的日期。 –

+0

沒有附加超過5個付款/付款日期的名稱。那是你在說什麼?如果是這樣,是否有一個過濾器可以限制創建的字段數量? –

1

您可以使用tidyr

library(dplyr) 
library(tidyr) 

pmts <- tibble(
    name = c("johndoe", "johndoe", "janedoe", "foo", "foo", "foo"), 
    pmt_amount = c(550L, 550L, 995L, 375L, 375L, 375L), 
    pmt_date = lubridate::mdy(c("9/1/16", "11/1/16", "12/15/16", "1/5/17", "3/5/17", "5/5/17")) 
) 

pmts 
#> # A tibble: 6 x 3 
#>  name pmt_amount pmt_date 
#>  <chr>  <int>  <date> 
#> 1 johndoe  550 2016-09-01 
#> 2 johndoe  550 2016-11-01 
#> 3 janedoe  995 2016-12-15 
#> 4  foo  375 2017-01-05 
#> 5  foo  375 2017-03-05 
#> 6  foo  375 2017-05-05 

pmts_long <- pmts %>% 
    group_by(name) %>% 
    arrange(name, pmt_date) %>% 
    mutate(pmt = row_number()) %>% 
    ungroup() %>% 
    complete(name, nesting(pmt)) %>% 
    fill(pmt_amount, .direction = "down") 

pmts_long 
#> # A tibble: 9 x 4 
#>  name pmt pmt_amount pmt_date 
#>  <chr> <int>  <int>  <date> 
#> 1  foo  1  375 2017-01-05 
#> 2  foo  2  375 2017-03-05 
#> 3  foo  3  375 2017-05-05 
#> 4 janedoe  1  995 2016-12-15 
#> 5 janedoe  2  995   NA 
#> 6 janedoe  3  995   NA 
#> 7 johndoe  1  550 2016-09-01 
#> 8 johndoe  2  550 2016-11-01 
#> 9 johndoe  3  550   NA 

pmts_wide <- pmts_long %>% 
    gather("key", "val", -name, -pmt_amount, -pmt) %>% 
    unite(pmt_number, key, pmt) %>% 
    spread(pmt_number, val) 

pmts_wide 
#> # A tibble: 3 x 5 
#>  name pmt_amount pmt_date_1 pmt_date_2 pmt_date_3 
#> * <chr>  <int>  <date>  <date>  <date> 
#> 1  foo  375 2017-01-05 2017-03-05 2017-05-05 
#> 2 janedoe  995 2016-12-15   NA   NA 
#> 3 johndoe  550 2016-09-01 2016-11-01   NA 
+0

謝謝!這工作很好。但是,這是我簡化示例數據的過錯,我需要爲此添加'Form.Title'和'Email'字段(如我在前面顯示的原始group_by代碼段中)。我試圖將它們添加到我認爲他們會在您編寫的代碼中去的地方,但我收到了錯誤。你能不能在代碼中顯示這些字段的位置? –