Pisahkan kerangka data yang besar menjadi daftar bingkai data berdasarkan nilai umum di kolom

88

Saya memiliki bingkai data dengan 10 kolom, mengumpulkan tindakan "pengguna", di mana salah satu kolom berisi ID (tidak unik, mengidentifikasi pengguna) (kolom 10). panjang bingkai data sekitar 750000 baris. Saya mencoba untuk mengekstrak frame data individu (sehingga mendapatkan daftar atau vektor frame data) yang dipisahkan oleh kolom yang berisi pengenal "pengguna", untuk mengisolasi tindakan aktor tunggal.

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

menghasilkan

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

Berikut ini bekerja sangat baik untuk saya pada sampel kecil (1000 baris):

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

dan kemudian mengakses elemen yang saya inginkan dengan jalur [1] misalnya.

Saat menerapkan pada bingkai data besar asli atau bahkan representasi matriks, ini mencekik mesin saya (RAM 4GB, MacOSX 10.6, R 2.15) dan tidak pernah selesai (saya tahu bahwa ada versi R yang lebih baru, tetapi saya yakin ini bukan masalah utama ).

Tampaknya pemisahan lebih berkinerja dan setelah waktu yang lama selesai, tetapi saya tidak tahu (pengetahuan R inferior) bagaimana cara memotong daftar vektor yang dihasilkan menjadi vektor matriks.

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

Saya telah mempertimbangkan juga menggunakan big.matrixdll, tetapi tanpa banyak keberhasilan yang akan mempercepat prosesnya.

MartinT
sumber

Jawaban:

104

Anda dapat dengan mudah mengakses setiap elemen dalam daftar menggunakan mis path[[1]]. Anda tidak dapat menempatkan kumpulan matriks ke dalam vektor atom dan mengakses setiap elemen. Matriks adalah vektor atom dengan atribut dimensi. Saya akan menggunakan struktur daftar yang dikembalikan oleh split, untuk itulah struktur itu dirancang. Setiap elemen daftar dapat menyimpan data dari berbagai jenis dan ukuran sehingga sangat serbaguna dan Anda dapat menggunakan *applyfungsi untuk mengoperasikan lebih lanjut pada setiap elemen dalam daftar. Contoh di bawah ini.

#  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

Akses setiap elemen menggunakan [[operator seperti ini:

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

Atau gunakan *applyfungsi untuk melakukan operasi lebih lanjut pada setiap elemen daftar. Misalnya, untuk mengambil mean dari data2kolom Anda bisa menggunakan sapply seperti ini:

sapply( out , function(x) mean( x$data2 ) )
#   1    2 
#3.75 6.25 
Simon O'Hanlon
sumber
2
Saya bertanya-tanya kinerja dlply(df, .(userid))dan menemukan bahwa itu buruk dibandingkan splitbahkan tanpa melibatkan jangka waktu require(plyr), terima kasih dan OP!
Francis
21

Dari versi 0.8.0, dplyrmenawarkan fungsi praktis yang disebut 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

Untuk tidak menyertakan kolom pengelompokan:

df %>%
 group_split(g, keep = FALSE)
tmfmnk
sumber
Apakah ada cara untuk memberi nama daftar menggunakan kolom pengelompokan yang dijatuhkan? Saya tahu saya bisa melakukan ini: tetapi bertanya-tanya apakah ada cara untuk melakukannya dalam nama dplyr? (F.vars.h1.list) <- unique (f.vars.to.agg.1h $ ActivityGroup)
d3hero23
9

Tersandung pada jawaban ini dan saya benar-benar menginginkan KEDUA grup (data yang berisi satu pengguna dan data yang berisi segalanya kecuali satu pengguna itu). Tidak perlu untuk spesifik dari posting ini, tetapi saya pikir saya akan menambahkan jika seseorang mencari masalah yang sama dengan saya di 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']]

Berikut tampilannya:

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
Aus_10
sumber