2015-06-23 4 views
5

ich einen Datenrahmen der folgende Form haben:rearrange data.frame die Reihenfolge der Produkte zu erhalten

df <- data.frame(client = c("client1", "client1", "client2", "client3", "client3"), 
       product = c("A", "B", "A", "D", "A"), 
       purchase_Date = c("2010-03-22", "2010-02-02", "2009-03-02", "2011-04-05", "2012-11-01")) 
df$purchase_Date <- as.Date(df$purchase_Date, format = "%Y-%m-%d") 

, die wie folgt aussieht:

client product purchase_Date 
1 client1  A 2010-03-02 
2 client1  B 2010-02-02 
3 client2  A 2009-03-02 
4 client3  D 2011-04-05 
5 client3  A 2012-11-01 

die ich möchte wie diese neu anordnen :

client purchase1 purchase2 
1 client1   B   A 
2 client2   A  <NA> 
3 client3   D   A 

so würde ich, welches Produkt, um herauszufinden, wie der erste, zweite, dritte und so weiter, jedes perso war n geordnet nach dem Kaufdatum. Ich kann leicht jeden einzeln mit data.table:

für die erste. aber ich habe keine Ahnung, wie man die gewünschte Ausgabe effizient erhält.

Antwort

7

Hier ist eine mögliche data.table Lösung (wenn Sie mehr als 10 Käufe haben, dann würde ich empfehlen die Verwendung von paste0 zu vermeiden und nur indx := seq_len(.N) verwenden statt, wie es könnte möglicherweise vermasseln die Bestellung)

setDT(df)[order(purchase_Date), indx := paste0("purchase", seq_len(.N)), by = client] 
dcast(df, client ~ indx, value.var = "product") 
#  client purchase1 purchase2 
# 1: client1   B   A 
# 2: client2   A  NA 
# 3: client3   D   A 

Vergleich zwischen frank() und order() Ansätze indx col zu erstellen:

require(data.table) 
set.seed(45L); 
dt = data.table(client = sample(paste("client", 1:1e4, sep=""), 1e6, TRUE)) 
dt[, `:=`(product = sample(paste("p", 1:200, sep=""), .N, FALSE), 
      purchase_Date = as.Date(sample(14610:16586, .N, FALSE), 
      origin = "1970-01-01")), by=client] 

system.time(dt[order(purchase_Date), indx := seq_len(.N), by = client]) 
# user system elapsed 
# 0.19 0.02 0.20 
system.time(dt[, purch_rank := frank(purchase_Date, ties.method = "dense"), by=client]) 
# user system elapsed 
# 3.94 0.00 3.98 
+1

Dies finde ich effizienter, da es einen Aufruf von 'frank()' für jedes 'by' vermeidet. 'seq_len()' sollte sehr vernachlässigbar sein ... wäre toll, Benchmark! – Arun

+4

Gerade Benchmark auf einer Million Zeilen mit 10000 Clients - 'frank = 2.6s' vs' order() = 0.5s'. Hinzugefügt [FR # 1197] (https://github.com/Rdatatable/data.table/issues/1197). – Arun

4

A dplyr/tidyr Ansatz:

library(dplyr) 
library(tidyr) 

df %>% 
    group_by(client) %>% 
    mutate(purch_rank = dense_rank(purchase_Date)) %>% 
    select(-purchase_Date) %>% 
    spread(purch_rank, product) 
#Source: local data frame [3 x 3] 
# 
# client 1 2 
#1 client1 B A 
#2 client2 A NA 
#3 client3 D A 

und ein möglicher data.table Ansatz:

library(data.table) #v 1.9.5+ currently from GitHub for "frank" 
setDT(df)[, purch_rank := frank(purchase_Date, ties.method = "dense"), by=client] 
dcast(df, client ~ purch_rank, value.var = "product") 
# client 1 2 
#1: client1 B A 
#2: client2 A NA 
#3: client3 D A 
+0

Es tut mir leid, meine Lösung ist Ihrer sehr ähnlich. Ich war beschäftigt, um es herauszufinden, ich habe es nicht bemerkt. – SabDeM

+0

@SabDeM, kein Problem –

+1

danke für das Zeigen auf die offensichtlichen nur einen Rang hinzufügen! ... oh Mann der Arbeitstag war zu lange – grrgrrbla

0

Hier ist meine Lösung mit dplyr und tidyr:

df %>% 
    group_by(client) %>% 
    select(-purchase_Date) %>% 
    mutate(purchase = seq_along(product)) %>% 
    spread(purchase, product) 
Source: local data frame [3 x 3] 

    client 1 2 
1 client1 A B 
2 client2 A NA 
3 client3 D A 

Ein leicht anderer Ansatz mit einem anderen Ausgang wäre mit der reshape2 Paket. Verwenden Sie einfach den vorherigen Code mit Ausnahme der letzten Zeile, die durch diese ersetzt werden:

dcast(client ~ product) 
Using purchase as value column: use value.var to override. 
    client A B D 
1 client1 1 2 NA 
2 client2 1 NA NA 
3 client3 2 NA 1 
+0

Ihre dplyr Ergebnisse sind falsch, weil Sie nicht die "Kaufdatum" Informationen verwenden. –

+0

Ich weiß, deshalb habe ich gesagt, das ist ein anderer Ansatz. Die Ausgabe zeigt nicht die gekauften Produkte an (was in diesem Fall eine Variable ist), sondern die Rangfolge, die sie hat. Die Frage natürlich nicht beantworten, aber vielleicht hilfreich. – SabDeM

+0

Sprechen Sie auch über den ersten Ansatz in Ihrer Antwort? –

Verwandte Themen