2015-06-03 5 views
6

Ho un frame di dati R che assomiglia:Come si ordina un frame di dati R in base all'id di richiesta e all'ID di richiesta precedente?

 
User |request_id |previous_request_id 
------------------------------------- 
A |9   |5 
A |3   |1 
A |5   |NA 
A |1   |9 
B |2   |8 
B |8   |7 
B |7   |NA 
B |4   |2 

Ogni riga corrisponde ad una richiesta di un particolare utente made. Ogni riga ha un ID utente, un ID richiesta e l'ID della richiesta precedente. Dove non ci sono richieste precedenti il ​​campo previous_request_id è NA.

Per ogni utente voglio ordinare ogni richiesta utilizzando la richiesta precedente id, con:

  • L'ordine che è 1 se il previous_request_id è NA
  • L'ordine che è 2 se il previous_request_id è uguale a un request_id con un ordine di 1
  • l'ordine che è 3 se il previous_request_id è uguale a un request_id con un ordine di 2
  • ecc

Il risultato delle regole di cui sopra applicata alla prima tabella dovrebbe essere simile:

 
User |request_id |previous_request_id |Order 
--------------------------------------------- 
A |9   |5     |2 
A |3   |1     |4 
A |5   |NA     |1 
A |1   |9     |3 
B |2   |8     |3 
B |8   |7     |2 
B |7   |NA     |1 
B |4   |2     |4 

C'è un modo per fare questo all'interno di R? Credo che un pacchetto di database grafico potrebbe essere il modo per farlo, ma finora non sono stato in grado di trovare nulla nella mia ricerca (incentrata sulla lingua Cypher di Neo4j).

Qualsiasi aiuto qui sarebbe molto apprezzato!

+0

è il tuo dati in Neo4j ? –

+0

Non è - è nel formato del frame di dati. – shancrane

risposta

0

Ci potrebbero essere modi molto più efficienti per farlo, ma ecco come lo farei usando solo cicli e ricorsione.

str <- "User |request_id |previous_request_id 
A |9   |5 
A |3   |1 
A |5   |NA 
A |1   |9 
B |2   |8 
B |8   |7 
B |7   |NA 
B |4   |2" 

tab <- read.table(textConnection(str), sep="|", header=TRUE) 
tab$order <- NA 

getOrder <- function(id){ 
    i <- which(tab$request_id == id) 
    if(is.na(tab$previous_request_id[i])){ 
     tab$order[i] <<- 1 
    } else { 
     tab$order[i] <<- getOrder(tab$previous_request_id[i]) + 1 
    } 
} 

for(i in 1:nrow(tab)){ 
    if(is.na(tab$order[i])){ 
     if(is.na(tab$previous_request_id[i])){ 
      tab$order[i] <- 1 
     } else { 
      tab$order[i] <- getOrder(tab$previous_request_id[i]) + 1 
     } 
    } 
} 

uscita:

User request_id previous_request_id order 
1 A    9     5  2 
2 A    3     1  4 
3 A    5     NA  1 
4 A    1     9  3 
5 B    2     8  3 
6 B    8     7  2 
7 B    7     NA  1 
8 B    4     2  4 
2

Ci sono molti modi per farlo, ma ecco cosa mi è venuta ...

df <- read.delim(text="User|request_id|previous_request_id 
A|9|5 
A|3|1 
A|5|NA 
A|1|9 
B|2|8 
B|8|7 
B|7|NA 
B|4|2", sep="|") 

df$order <- rep(NA, nrow(df)) 
df$order[is.na(df$previous_request_id)] <- 1 
df$order[df$order[match(df$previous_request_id, df$request_id)] == 1] <- 2 
df$order[df$order[match(df$previous_request_id, df$request_id)] == 2] <- 3 
df$order[df$order[match(df$previous_request_id, df$request_id)] == 3] <- 4 

meno di notare che stiamo ripetendo lo stesso codice (quasi) più e più volte. Siamo in grado di creare un ciclo di accorciare il codice un po '...

max_user_len <- max(table(df$User)) 
df$order <- rep(NA, nrow(df)) 
df$order[is.na(df$previous_request_id)] <- 1 
sapply(1:max_user_len, function(x)df$order[df$order[match(df$previous_request_id, df$request_id)] == x] <<- x+1) 
> df$order 
[1] 2 4 1 3 3 2 1 4 
0

Con igraph questo potrebbe essere fatto il calcolo del percorso più breve dalla prima richiesta. Questo potrebbe funzionare:

require(igraph) 
df[]<-lapply(df,as.character) 
unlist(
    lapply(split(df,df$User), 
     function(x) { 
     graphtmp<-graph.edgelist(na.omit(as.matrix(x[,3:2]))) 
     path<-as.vector(shortest.paths(graphtmp,x$request_id[is.na(x$previous_request_id)],x$request_id)) 
     path+1 
     }),use.names=F) 
#[1] 2 4 1 3 3 2 1 4 
0

Non so come questo confronto ad altre soluzioni in quanto utilizza un ciclo for, ma le operazioni di DataTable e plyr dovrebbe contribuire ad accelerare alcuni componenti ricorsive:

## DATA UPLOAD 

df <- read.delim(text="User|request_id|previous_request_id 
A|9|5 
A|3|1 
A|5|NA 
A|1|9 
B|2|8 
B|8|7 
B|7|NA 
B|4|2", sep="|") 

## PACKAGE LOAD 

require(data.table) 
require(plyr) 

## GET DATA INTO RIGHT FORMAT 

df <- data.table(df) 
df[, User := as.character(User)] 
df[, request_id := as.character(request_id)] 
df[, previous_request_id := as.character(previous_request_id)] 

## THE ACTUAL PROCESS 

# Create vector of user ids 

user.list <- unique(df$User) 

# Setkey to speed up filtering 

setkey(df,User) 

get_order <- function(user,df) { 

    # Consider only one user at a time 

    s.df <- df[user] 

    # Create an empty ordering column 

    s.df$ord <- as.numeric(NA) 

    # Redefine NA as 0 

    s.df[is.na(previous_request_id) == TRUE,]$previous_request_id <- "0" 

    # Set seed to 0 

    seed <- "0" 

    # Setkey to speed up filtering 

    setkey(s.df,previous_request_id) 

    for (i in 1:NROW(s.df)) { 

    # Filter by seed and define ord as i 

    s.df[seed]$ord <- i 

    # Define new seed based on filtered request_id 

    seed <- s.df[seed]$request_id} 

    return(s.df)} 

# Loop through user vector and rbindlist to rebind the output 

rebuilt <- rbindlist(llply(.data = user.list, .fun = function(x) {get_order(x,df)})) 
Problemi correlati