แบ่งดาต้าเฟรมขนาดใหญ่เป็นรายการของเฟรมข้อมูลตามค่าทั่วไปในคอลัมน์


88

ฉันมีกรอบข้อมูลที่มี 10 คอลัมน์ซึ่งรวบรวมการกระทำของ "ผู้ใช้" โดยที่คอลัมน์ใดคอลัมน์หนึ่งมี ID (ไม่ใช่เฉพาะระบุผู้ใช้) (คอลัมน์ 10) ความยาวของกรอบข้อมูลประมาณ 750000 แถว ฉันกำลังพยายามแยกเฟรมข้อมูลแต่ละรายการ (ดังนั้นการรับรายการหรือเวกเตอร์ของเฟรมข้อมูล) แยกตามคอลัมน์ที่มีตัวระบุ "ผู้ใช้" เพื่อแยกการกระทำของนักแสดงคนเดียว

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

ส่งผลให้

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

ต่อไปนี้ใช้งานได้ดีสำหรับฉันในตัวอย่างขนาดเล็ก (1,000 แถว):

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

จากนั้นจึงเข้าถึงองค์ประกอบที่ฉันต้องการตามเส้นทาง [1] เช่น

เมื่อใช้กับ data frame ขนาดใหญ่ดั้งเดิมหรือแม้แต่การแสดงเมทริกซ์สิ่งนี้จะทำให้เครื่องของฉันหายไป (RAM 4GB, MacOSX 10.6, R 2.15) และไม่เสร็จสมบูรณ์ (ฉันรู้ว่ามีรุ่น R ที่ใหม่กว่าอยู่ แต่ฉันเชื่อว่านี่ไม่ใช่ปัญหาหลัก ).

ดูเหมือนว่าการแบ่งจะมีประสิทธิภาพมากกว่าและหลังจากเสร็จสิ้นเป็นเวลานาน แต่ฉันไม่รู้ว่า (ความรู้ R ที่ด้อยกว่า) จะรวมรายการเวกเตอร์ที่เป็นผลลัพธ์เป็นเวกเตอร์ของเมทริกซ์ได้อย่างไร

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

ฉันได้พิจารณาการใช้งานbig.matrixฯลฯ ด้วย แต่ไม่ประสบความสำเร็จมากนักที่จะเร่งกระบวนการ

คำตอบ:


104

path[[1]]คุณสามารถได้อย่างง่ายดายเพียงเข้าถึงแต่ละองค์ประกอบในรายการใช้เช่น คุณไม่สามารถใส่ชุดเมทริกซ์ลงในเวกเตอร์อะตอมและเข้าถึงแต่ละองค์ประกอบได้ เมทริกซ์คือเวกเตอร์อะตอมที่มีคุณสมบัติมิติ ฉันจะใช้โครงสร้างรายการที่ส่งคืนโดยsplitเป็นสิ่งที่ออกแบบมาเพื่อ องค์ประกอบรายการแต่ละรายการสามารถเก็บข้อมูลประเภทและขนาดต่างๆได้ดังนั้นจึงมีความหลากหลายมากและคุณสามารถใช้*applyฟังก์ชันเพื่อดำเนินการเพิ่มเติมกับแต่ละองค์ประกอบในรายการได้ ตัวอย่างด้านล่าง

#  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

เข้าถึงแต่ละองค์ประกอบโดยใช้ตัว[[ดำเนินการดังนี้:

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

หรือใช้*applyฟังก์ชันเพื่อดำเนินการเพิ่มเติมในแต่ละองค์ประกอบรายการ ตัวอย่างเช่นหากต้องการหาค่าเฉลี่ยของdata2คอลัมน์คุณสามารถใช้ sapply ดังนี้:

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

2
ฉันสงสัยในประสิทธิภาพของdlply(df, .(userid))และพบว่ามันไม่ดีเมื่อเทียบกับsplitแม้ว่าจะไม่เกี่ยวข้องกับเวลาทำงานของrequire(plyr)ขอบคุณและ OP!
Francis

21

จากเวอร์ชัน 0.8.0 dplyrมีฟังก์ชันที่มีประโยชน์ที่เรียกว่า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

ในการไม่รวมคอลัมน์การจัดกลุ่ม:

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

มีวิธีตั้งชื่อรายการโดยใช้คอลัมน์การจัดกลุ่มที่ลดลงหรือไม่? ฉันรู้ว่าฉันทำได้ แต่สงสัยว่ามีวิธีทำภายใน dplyr หรือไม่ชื่อ (f.vars.h1.list) <- unique (f.vars.to.agg.1h $ ActivityGroup)
d3hero23

9

สะดุดกับคำตอบนี้และฉันต้องการทั้งสองกลุ่มจริงๆ (ข้อมูลที่มีผู้ใช้คนนั้นและข้อมูลที่มีทุกอย่างยกเว้นผู้ใช้คนนั้น) ไม่จำเป็นสำหรับข้อมูลเฉพาะของโพสต์นี้ แต่ฉันคิดว่าฉันจะเพิ่มในกรณีที่มีคนเข้าร่วมปัญหาเดียวกับฉัน

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

นี่คือสิ่งที่ดูเหมือน:

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.