Sütundaki ortak değere göre büyük bir veri çerçevesini bir veri çerçevesi listesine bölme


88

"Kullanıcıların" eylemlerini toplayan 10 sütunlu bir veri çerçevem ​​var, burada sütunlardan biri bir kimlik içeriyor (benzersiz değil, kullanıcıyı tanımlayan) (sütun 10). veri çerçevesinin uzunluğu yaklaşık 750000 satırdır. Tek bir aktörün eylemlerini izole etmek için "kullanıcı" tanımlayıcısını içeren sütuna ayrı ayrı veri çerçevelerini çıkarmaya çalışıyorum (bu nedenle veri çerçevelerinin bir listesini veya vektörünü elde ediyorum).

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

sonuçlanan

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
...)

Aşağıdakiler, küçük bir örnekte (1000 sıra) benim için çok iyi çalışıyor:

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

ve sonra örneğin [1] yollarından istediğim öğeye erişiyorum.

Orijinal büyük veri çerçevesine veya hatta bir matris sunumuna uygularken, bu, makinemi (4GB RAM, MacOSX 10.6, R 2.15) boğuyor ve asla tamamlanmıyor (daha yeni bir R sürümünün var olduğunu biliyorum, ancak bunun ana sorun olmadığına inanıyorum ).

Görünüşe göre bölünme daha performanslı ve uzun bir süre sonra tamamlanıyor, ancak elde edilen vektör listesini bir matris vektörüne nasıl parçalayacağımı (daha düşük R bilgisi) bilmiyorum.

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

Ben de big.matrixvb kullanmayı düşündüm , ancak süreci hızlandıracak çok fazla başarı olmazsa.

Yanıtlar:


104

Listedeki her bir öğeye örn path[[1]]. Kullanarak kolayca erişebilirsiniz . Bir atomik vektöre bir dizi matris koyup her bir öğeye erişemezsiniz. Bir matris, boyut niteliklerine sahip atomik bir vektördür. Döndüren liste yapısını kullanırdım, splitbunun için tasarlandı. Her liste öğesi, farklı tür ve boyutlardaki verileri tutabilir, bu nedenle çok yönlüdür ve *applylistedeki her öğe üzerinde daha fazla işlem yapmak için işlevleri kullanabilirsiniz . Aşağıdaki örnek.

#  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

[[Operatörü şu şekilde kullanarak her öğeye erişin :

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

Veya *applyher liste öğesi üzerinde daha fazla işlem yapmak için bir işlev kullanın. Örneğin, data2sütunun ortalamasını almak için şu şekilde sapply kullanabilirsiniz:

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

2
Performansını merak ediyordum ve çalışma süresine dahil olmadan bile dlply(df, .(userid))kötü olduğunu gördüm , teşekkür ederim ve OP! splitrequire(plyr)
Francis

21

0.8.0 sürümünden itibaren, şu dplyradında kullanışlı bir işlev sunar 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

Gruplama sütununu dahil etmemek için:

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

Listeyi bırakılan gruplama sütununu kullanarak adlandırmanın bir yolu var mı? Bunu yapabileceğimi biliyorum: ancak dplyr? Names (f.vars.h1.list) <- unique (f.vars.to.agg.1h $ ActivityGroup)
d3hero23

9

Bu yanıta tökezledim ve aslında BOTH gruplarını istedim (bu tek kullanıcıyı içeren veriler ve o kullanıcı dışındaki her şeyi içeren veriler). Bu yazının özellikleri için gerekli değil, ancak birinin benimle aynı sorunu araştırması durumunda ekleyeceğimi düşündüm.

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']]

Göründüğü gibi:

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
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.