Question

J'ai un tableau de données qui contient des informations sur les personnes et les projets en tant que tels:

person_id | project_id | action | time
--------------------------------------
        1 |          1 |      w |    1
        1 |          2 |      w |    2
        1 |          3 |      w |    2
        1 |          3 |      r |    3
        1 |          3 |      w |    4
        1 |          4 |      w |    4
        2 |          2 |      r |    2
        2 |          2 |      w |    3

Je voudrais augmenter ces données avec quelques champs supplémentaires appelés "First_time" et "First_time_project" qui identifient collectivement toute action par cette personne et la première fois que le développeur a vu une action sur le projet. En fin de compte, les données devraient ressembler à ceci:

person_id | project_id | action | time | first_time | first_time_project
------------------------------------------------------------------------
        1 |          1 |      w |    1 |          1 |                  1
        1 |          2 |      w |    2 |          1 |                  2
        1 |          3 |      w |    2 |          1 |                  2
        1 |          3 |      r |    3 |          1 |                  2
        1 |          3 |      w |    4 |          1 |                  2
        1 |          4 |      w |    4 |          1 |                  4
        2 |          2 |      r |    2 |          2 |                  2
        2 |          2 |      w |    3 |          2 |                  2

Ma façon naïve de faire ça pour écrire quelques boucles:

for (pid in unique(data$person_id)) {
    data[data$pid==pid, "first_time"] = min(data[data$pid==pid, "time"])
    for (projid in unique(data[data$pid==pid, "project_id"])) {
        data[data$pid==pid & data$project_id==projid, "first_time_project"] = min(data[data$pid==pid & data$project_id==projid, "time"]
    }
}

Maintenant, il ne faut pas un génie pour voir que cela va être glacial avec les boucles doublement imbriquées. Cependant, je ne peux pas trouver un moyen de gérer cela dans R. J'émule un peu le groupe par option pour SQL. Je sais que pour pouvoir aider, mais je ne peux pas comprendre comment faire plusieurs tranches.

Des conseils sur la façon de passer mon code de glaciaire à quelque chose d'un peu plus rapidement? Je serais content d'un escargot en ce moment.

Était-ce utile?

La solution

Essayer ave :

transform(data, 
   first_time = ave(time, person_id, FUN = min),
   first_time_project = ave(time, person_id, project_id, drop = TRUE, FUN = min)
)

Autres conseils

La combinaison du Plyr et de la transformation de Hadley est puissante. Si je comprends correctement votre question, alors:

foo <- ddply(foo, .(person_id), transform, first_time=min(time))
foo <- ddply(foo, .(person_id, project_id), transform, 
  first_time_project=min(time))

Si la vitesse est ce que vous recherchez, alors data.table est la voie à suivre.

library(data.table)
DT <- data.table(foo)
DT[, first_time := min(time), by = person_id]
DT[, first_time_project := min(time), by = list(person_id, project_id)]

Solution rapide et sale sans boucles

library(plyr)


# function to get first time by any person/project
fp <- function(dat) 
{
dat$first_time=min(dat$time)
ftp <- function(d) { d$first_time_project=min(d$time); return (d) }
dat=ddply(dat, .(project_id), ftp)
return (dat)
}


#this single call should give you the result you want
result=ddply(data, .(person_id), fp) 

Une façon rapide à laquelle je peux penser:

foo <- data.frame(
       person_id=rep(1:5,each=6),
       project_id=sample(1:5,30,T),
       time=sample(1:30))

first_time <- aggregate(foo$time, list(foo$person_id), min)

foo$first_time <- first_time[ match(foo$person_id,first_time[,1]),2]

bar <- subset(foo, time==first_time)

foo$first_time_project <- bar$project_id[match(foo$person_id, bar$person_id)]
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top