2
votes

R: Diviser le dataframe en liste par groupe et itération de ligne

J'ai un dataframe comme celui-ci:

split_list <- split(startingframe,list(startingframe$group1,startingframe$time))

... que j'essaie de manipuler en une liste qui se divise par groupe et chaque 'itération' du temps code> colonne, les résultats ressemblent à ceci:

 $a1
  group1 time othercolumn
1      a    1    -0.13889

$a2
  group1 time othercolumn
1      a    1   -0.138890
2      a    2    1.199813

$a3
  group1 time othercolumn
1      a    1  -0.1388900
2      a    2   1.1998129
3      a    3  -0.7477224

$b1
  group1 time othercolumn
4      b    1  -0.5752482

$b2
  group1 time othercolumn
4      b    1  -0.5752482
5      b    2  -0.2635815

$b3
  group1 time othercolumn
4      b    1  -0.5752482
5      b    2  -0.2635815
6      b    3  -0.4554921

Je pense que j'ai juste besoin du bit d'itération incorporé dans ce code:

set.seed(34)
startingframe <-  data.frame(
  group1=factor(rep(c("a","b"),each=3,times=1)),
  time=rep(1:3,each=1,times=2),
  othercolumn=rnorm(1:6)
)

EDIT: J'ai peut-être simplifié à l'extrême le problème d'origine, mais le vrai jeu de données contient des colonnes supplémentaires qui devraient être introduites dans la liste.


0 commentaires

3 Réponses :


1
votes

Ne pas fractionner ici, mais générer la sortie souhaitée.

genlist = function(l,t){return((data.frame(group1=rep(x = l,times=t),time=seq(from=1,to = t,by = 1))))}

mapply(genlist,startingframe$group1,startingframe$time,SIMPLIFY = FALSE)


1 commentaires

Y a-t-il un moyen que cela fonctionne si nous voulions ajouter des colonnes supplémentaires dans le tableau?



0
votes

Une façon de faire serait d'utiliser lapply dans une autre lapply

lapply(levels(startingframe$group1), function(group) {
  df = startingframe[startingframe$group1 == group, ]
  lapply(df$time, function(time) {
    df[df$time %in% 1:time, ]
  })
})

[[1]]
[[1]][[1]]
  group1 time
1      a    1

[[1]][[2]]
  group1 time
1      a    1
2      a    2

[[1]][[3]]
  group1 time
1      a    1
2      a    2
3      a    3


[[2]]
[[2]][[1]]
  group1 time
4      b    1

[[2]][[2]]
  group1 time
4      b    1
5      b    2

[[2]][[3]]
  group1 time
4      b    1
5      b    2
6      b    3


0 commentaires

2
votes

Vous pouvez utiliser head pour chaque nombre de la séquence 1: nrow (x) , pour chaque sous-groupe x de vos données

inds <- 
  lapply(split(seq(nrow(df)), df$group1), function(x) 
    lapply(1:length(x), function(y) x[seq(y)]))

inds
# $`a`
# $`a`[[1]]
# [1] 1
# 
# $`a`[[2]]
# [1] 1 2
# 
# $`a`[[3]]
# [1] 1 2 3
# 
# 
# $b
# $b[[1]]
# [1] 4
# 
# $b[[2]]
# [1] 4 5
# 
# $b[[3]]
# [1] 4 5 6

df[inds$b[[2]]]
#    group1 time
# 1:      b    1
# 2:      b    2

Vous n'aurez peut-être pas besoin de créer une liste de tous ces dataframes, vous pouvez simplement créer une liste d'index et les utiliser si nécessaire.

out <- lapply(split(df, df$group1), function(x) lapply(1:nrow(x), head, x = x))
out <- unlist(out, recursive = F)

out
# $`a1`
#    group1 time
# 1:      a    1
# 
# $a2
#    group1 time
# 1:      a    1
# 2:      a    2
# 
# $a3
#    group1 time
# 1:      a    1
# 2:      a    2
# 3:      a    3
# 
# $b1
#    group1 time
# 1:      b    1
# 
# $b2
#    group1 time
# 1:      b    1
# 2:      b    2
# 
# $b3
#    group1 time
# 1:      b    1
# 2:      b    2
# 3:      b    3


2 commentaires

Je suppose que le problème ici est qu'il crée une liste de listes?


Vous pouvez utiliser unlist si vous le souhaitez sous forme de liste unique de blocs de données. J'ai édité la réponse.