107 votes

Diviser un grand cadre de données en une liste de cadres de données basés sur la valeur commune dans la colonne.

J'ai un cadre de données avec 10 colonnes, collectant les actions des "utilisateurs", où l'une des colonnes contient un ID (non unique, identifiant l'utilisateur) (colonne 10). La longueur du cadre de données est d'environ 750000 lignes. J'essaie d'extraire des cadres de données individuels (donc d'obtenir une liste ou un vecteur de cadres de données) divisés par la colonne contenant l'identifiant "utilisateur", pour isoler les actions d'un seul acteur.

ID | Data1 | Data2 | ... | UserID
1  | aaa   | bbb   | ... | u_001
2  | aab   | bb2   | ... | u_001
3  | aac   | bb3   | ... | u_001
4  | aad   | bb4   | ... | u_002

qui se traduit par

list(
ID | Data1 | Data2 | ... | UserID
1  | aaa   | bbb   | ... | u_001
2  | aab   | bb2   | ... | u_001
3  | aac   | bb3   | ... | u_001
,
4  | aad   | bb4   | ... | u_002
...)

La méthode suivante fonctionne très bien pour moi sur un petit échantillon (1000 lignes) :

paths = by(smallsampleMat, smallsampleMat[,"userID"], function(x) x)

et ensuite accéder à l'élément que je veux par paths[1] par exemple.

Lorsqu'il est appliqué sur le grand cadre de données original ou même sur une représentation matricielle, il étouffe ma machine (4 Go de RAM, MacOSX 10.6, R 2.15) et ne se termine jamais (je sais qu'il existe une version plus récente de R, mais je pense que ce n'est pas le problème principal).

Il semble que split soit plus performant et se termine après un long moment, mais je ne sais pas (connaissance inférieure de R) comment transformer la liste de vecteurs résultante en un vecteur de matrices.

path = split(smallsampleMat, smallsampleMat[,10]) 

J'ai envisagé d'utiliser également big.matrix etc., mais sans grand succès qui permettrait d'accélérer le processus.

122voto

Simon O'Hanlon Points 27680

Vous pouvez tout aussi bien accéder à chaque élément de la liste en utilisant, par exemple, les méthodes suivantes path[[1]] . Vous ne pouvez pas mettre un ensemble de matrices dans un vecteur atomique et accéder à chaque élément. Une matrice est un vecteur atomique avec des attributs de dimension. J'utiliserais la structure de liste renvoyée par split c'est ce pour quoi il a été conçu. Chaque élément de liste peut contenir des données de types et de tailles différents, ce qui en fait un outil très polyvalent. *apply pour poursuivre les opérations sur chaque élément de la liste. Exemple ci-dessous.

#  For reproducibile data
set.seed(1)

#  Make some data
userid <- rep(1:2,times=4)
data1 <- replicate(8 , paste( sample(letters , 3 ) , collapse = "" ) )
data2 <- sample(10,8)
df <- data.frame( userid , data1 , data2 )

#  Split on userid
out <- split( df , f = df$userid )
#$`1`
#  userid data1 data2
#1      1   gjn     3
#3      1   yqp     1
#5      1   rjs     6
#7      1   jtw     5

#$`2`
#  userid data1 data2
#2      2   xfv     4
#4      2   bfe    10
#6      2   mrx     2
#8      2   fqd     9

Accédez à chaque élément en utilisant le [[ opérateur comme ça :

out[[1]]
#  userid data1 data2
#1      1   gjn     3
#3      1   yqp     1
#5      1   rjs     6
#7      1   jtw     5

Ou utilisez un *apply pour effectuer d'autres opérations sur chaque élément de la liste. Par exemple, pour prendre la moyenne des data2 colonne vous pourriez utiliser spply comme ceci :

sapply( out , function(x) mean( x$data2 ) )
#   1    2 
#3.75 6.25

39voto

tmfmnk Points 8978

Depuis la version 0.8.0, dplyr offre une fonction pratique appelée group_split() :

# On sample data from @Aus_10

df %>%
  group_split(g)

[[1]]
# A tibble: 25 x 3
   ran_data1 ran_data2 g    
       <dbl>     <dbl> <fct>
 1     2.04      0.627 A    
 2     0.530    -0.703 A    
 3    -0.475     0.541 A    
 4     1.20     -0.565 A    
 5    -0.380    -0.126 A    
 6     1.25     -1.69  A    
 7    -0.153    -1.02  A    
 8     1.52     -0.520 A    
 9     0.905    -0.976 A    
10     0.517    -0.535 A    
# … with 15 more rows

[[2]]
# A tibble: 25 x 3
   ran_data1 ran_data2 g    
       <dbl>     <dbl> <fct>
 1     1.61      0.858 B    
 2     1.05     -1.25  B    
 3    -0.440    -0.506 B    
 4    -1.17      1.81  B    
 5     1.47     -1.60  B    
 6    -0.682    -0.726 B    
 7    -2.21      0.282 B    
 8    -0.499     0.591 B    
 9     0.711    -1.21  B    
10     0.705     0.960 B    
# … with 15 more rows

Pour ne pas inclure la colonne de regroupement :

df %>%
 group_split(g, keep = FALSE)

14voto

Aus_10 Points 158

Je suis tombé sur cette réponse et je voulais en fait les DEUX groupes (données contenant cet utilisateur et données contenant tout sauf cet utilisateur). Ce n'est pas nécessaire pour les spécificités de ce message, mais j'ai pensé que je devais ajouter au cas où quelqu'un chercherait le même problème que moi sur Google.

df <- data.frame(
     ran_data1=rnorm(125),
     ran_data2=rnorm(125),
     g=rep(factor(LETTERS[1:5]), 25)
 )

test_x = split(df,df$g)[['A']]
test_y = split(df,df$g!='A')[['TRUE']]

Voilà à quoi ça ressemble :

head(test_x)
            x          y g
1   1.1362198  1.2969541 A
6   0.5510307 -0.2512449 A
11  0.0321679  0.2358821 A
16  0.4734277 -1.2889081 A
21 -1.2686151  0.2524744 A

> head(test_y)
            x          y g
2 -2.23477293  1.1514810 B
3 -0.46958938 -1.7434205 C
4  0.07365603  0.1111419 D
5 -1.08758355  0.4727281 E
7  0.28448637 -1.5124336 B
8  1.24117504  0.4928257 C

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X