10
votes

Comment ajouter de la valeur cumulativement dans un vecteur dans r

J'ai un ensemble de données qui ressemble à ce xxx

ici, job2 désigne une variable factice indiquant si une personne était un manager Au cours de cette année ou non. Je veux faire deux choses à ce jeu de données: premièrement, je veux seulement conserver la ligne lorsque la personne est devenue patron pour la première fois. Deuxièmement, j'aimerais voir des années cumulatives qu'une personne a fonctionné comme un manager cumu_job2 . Ainsi, je voudrais avoir: xxx

J'ai changé mes exemples et inclus le poste de travail, car cela reflète plus ce que je veux faire avec le jeu de données d'origine. Les réponses de ce fil ne fonctionne que lorsqu'il n'y a que des gestionnaires et des patrons dans l'ensemble de données - de sorte que toute suggestion pour la fabrication de ce travail serait formidable. Je serai très reconnaissant !!


0 commentaires

5 Réponses :


11
votes

contribué par Matthew Dowle: xxx

explication

  1. Prenez le jeu de données
  2. Exécutez un filtre et ajoutez une colonne dans chaque S UBSet de d ATA ( .sd )
  3. groupé par nom et travail

    Les versions plus anciennes:

    Vous avez deux fractions différentes applicables à des combines ici. Un pour obtenir les emplois cumulatifs et l'autre pour obtenir la première rangée du statut de patron. Voici une implémentation dans data.Table. / code> où nous effectuons essentiellement chaque analyse séparément (bien, type de), puis collectez tout au même endroit avec RBind . La principale chose à noter est la pièce by = id , qui signifie essentiellement que les autres expressions sont évaluées pour chaque groupe ID dans les données, ce qui était ce que vous avez correctement noté manquait. De votre tentative. xxx

    Remarque Ce tableau suppose est trié par année dans chaque ID , mais si ce n'est pas suffisamment facile à réparer.


    Vous pouvez également accéder à la même chose avec: xxx

    L'idée est d'obtenir essentiellement les numéros de ligne où la condition correspond à la condition (avec < code> .Je - variable interne), puis sous-ensemble dt sur ces numéros de ligne (le $ V1 partie), puis effectuez simplement la somme cumulative.


9 commentaires

Merci beaucoup! J'ai une erreur si - Type de RHS ('Integer') doit correspondre à LHS ('Double'). Pour vérifier et contraindre aurait trop d'impact sur la performance pour les cas les plus rapides. Changez le type de la colonne cible ou coerce le RHS de: = vous-même (par exemple en utilisant 1L au lieu de 1)


Je ne comprends pas vraiment cela parce que j'ai tourné les vecteurs ID et Job2 en vecteurs entier à travers AS.Integer Command ....


J'ai lu Stackoverflow.com/Questtions/16361225/... et résolu le problème - tout simplement cumujob: = AS.numérique (Cumsum (Job2))) à la place.


En ce qui concerne la lisibilité, j'irais avec: dt [ .sd [travail! = "Patron" | Année == min (année)] [ cumjob: = cumsum (job2)], by = liste (nom, travail)]


@eddi hi - j'ai une autre question! Donc, si j'ai d'autres postes que les gestionnaires, comment puissierais-je conserver toutes les informations? Je n'ai pas bien précisé cette partie dans ma question, mais je pense que DT [Job2 == 1] Cela fait que cela vous achemine beaucoup d'informations dans mon ensemble de données.


Pour le dernier code, je reçois une erreur dans [. Data.frame (exentacc , .sd [ccmem == 0 | année == min (année)] [: argument non utilisé (par = liste (nom, Prov.1))


Le deuxième code provoque une même erreur d'erreur aussi - argument inutilisé (by = liste (nom1, CCMEM))


@ Rusuer9000, assurez-vous d'ajouter la Ligne Bibliothèque (Data.Table) Avant d'exécuter cette ligne. Le dernier fonctionne bien pour moi. Je n'ai pas testé le second. Si le package n'est pas installé, vous devrez alors exécuter installer.backages ("data.table") premier.


@ Rusuer9000 Vous avez déjà cette information dans les données, au lieu de penser à la manière de représenter cette information comme un numéro, que diriez-vous de sauter cette partie et d'aller directement à la prochaine étape de ce que vous voulez faire.



0
votes

@ Brodieg est bien meilleur:

les données forte> p> xxx pré>

#le code: strong> P >

inds1 <- rle(dat$job2)
inds2 <- cumsum(inds1[[1]])[inds1[[2]] == 1] + 1

ends <- cumsum(inds1[[1]])
starts <- c(1, head(ends + 1, -1))
inds3 <- mapply(":", starts, ends)
dat$id <- rep(1:length(inds3), sapply(inds3, length))
dat <- do.call(rbind, lapply(split(dat[, 1:5], dat$id ), function(x) {
    if(x$job2[1] == 0){ 
        x$cumu_job2 <- rep(0, nrow(x))
    } else { 
        x$cumu_job2 <- 1:nrow(x)
    }
    x
}))


keeps <- dat$job2 > 0
keeps[inds2] <- TRUE
dat2 <- data.frame(dat[keeps, ], row.names = NULL)
dat2

##    id name year     job job2 cumu_job2
## 1   1 Jane 1980 Manager    1         1
## 2   1 Jane 1981 Manager    1         2
## 3   1 Jane 1982 Manager    1         3
## 4   1 Jane 1983 Manager    1         4
## 5   1 Jane 1984 Manager    1         5
## 6   1 Jane 1985 Manager    1         6
## 7   2 Jane 1986    Boss    0         0
## 8   3  Bob 1985 Manager    1         1
## 9   3  Bob 1986 Manager    1         2
## 10  3  Bob 1987 Manager    1         3
## 11  4  Bob 1988    Boss    0         0


2 commentaires

Devinez que vous avez une chose contre succinct?


@psguy Je suppose que vous avez une chose contre les manières? Votre réponse était très succincte cependant.



22
votes

voici la solution dplyr dplyr pour le même problème.

Remarque: assurez-vous que stringsasfactors = false en lisant dans les données. < Pré> xxx

sortie: xxx

explication

  1. Prenez le jeu de données
  2. groupe par nom et travail
  3. Filtrer chaque groupe à base d'état
  4. Ajouter cumu_job2 colonne.

7 commentaires

La même idée sur le filtrage peut être utilisée avec data.table : dt [ liste (cum_job2 = cumsum (job2 [travail! = "Boss" | Année == min (année)]) ), par = c ("nom", "travail")]


@Ramnath J'aimerais savoir pourquoi cela ne fonctionne pas pour moi - je ne peux pas installer dplyr et%.% N'est pas une fonction.


%.% est une fonction dans dplyr . dplyr est sur Cran, il devrait donc être simple d'installer à l'aide de install_packages .


@Ramnath Avertissement dans Install.Packages: Le package 'dplyr' n'est pas disponible (pour la version 3.0.0) quelle version r travaillez-vous?


@Ramnath J'ai aussi essayé devtools :: install_github ("hadley / dplyr") mais il dit que l'erreur client: 404 non trouvé


Donc, j'ai mis à jour r mais cela n'a pas fonctionné - il vient de créer un cumul de Job2 jusqu'à la fin (quelle que soit chaque observation)


Je ne comprends pas quelle sortie vous avez eue. Une chose à prendre soin est de vous assurer que plyr n'est pas chargé en même temps que dplyr , car cela pourrait entraîner des conflits. J'ai mis à jour ma réponse avec la sortie, ce que je crois, c'est ce que vous recherchiez.



1
votes

Je pense que cela fait ce que vous voulez, bien que les données soient triées comme vous l'avez présentée.

my.df <- read.table(text = '
id  name    year    job    job2
1   Jane    1980    Worker  0
1   Jane    1981    Manager 1
1   Jane    1982    Manager 1
1   Jane    1983    Manager 1
1   Jane    1984    Manager 1
1   Jane    1985    Manager 1
1   Jane    1986    Boss    0
1   Jane    1987    Boss    0
2   Bob     1985    Worker  0
2   Bob     1986    Worker  0
2   Bob     1987    Manager 1
2   Bob     1988    Boss    0
2   Bob     1989    Boss    0
2   Bob     1990    Boss    0
2   Bob     1991    Boss    0
2   Bob     1992    Boss    0
', header = TRUE, stringsAsFactors = FALSE)

my.seq <- data.frame(rle(my.df$job)$lengths)

my.df$cumu_job2 <- as.vector(unlist(apply(my.seq, 1, function(x) seq(1,x))))

my.df2 <- my.df[!(my.df$job=='Boss' & my.df$cumu_job2 != 1),]
my.df2$cumu_job2[my.df2$job != 'Manager'] <- 0

   id name year     job job2 cumu_job2
1   1 Jane 1980  Worker    0         0
2   1 Jane 1981 Manager    1         1
3   1 Jane 1982 Manager    1         2
4   1 Jane 1983 Manager    1         3
5   1 Jane 1984 Manager    1         4
6   1 Jane 1985 Manager    1         5
7   1 Jane 1986    Boss    0         0
9   2  Bob 1985  Worker    0         0
10  2  Bob 1986  Worker    0         0
11  2  Bob 1987 Manager    1         1
12  2  Bob 1988    Boss    0         0


0 commentaires

3
votes

Voici une solution de base utilisant dans et AVE . Nous supposons que l'entrée est df et que les données sont triées comme dans la question. xxx

révision: utilise maintenant dans . < / p>


0 commentaires