Разбить большой фрейм данных на список фреймов данных на основе общего значения в столбце


у меня есть фрейм данных с 10 столбцами, собирающий действия "пользователей", где один из столбцов содержит идентификатор (не уникальный, идентифицирующий пользователя)(столбец 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
...)

следующие работы очень ну для меня на небольшой выборке (1000 строк):

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

а затем доступ к элементу я хочу по путям[1] например.

при применении к исходному большому фрейму данных или даже матричному представлению это душит мою машину ( 4GB RAM, MacOSX 10.6, R 2.15) и никогда не завершается (я знаю, что существует более новая версия R, но я считаю, что это не главная проблема).

кажется, что раскол является более производительным, и после долгого времени завершается, но я не знаю (подчиненное знание R) как собрать результирующий список векторов в вектор матриц.

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

я рассматривал также использование big.matrix и т. д., Но без особого успеха, что бы ускорить процесс.

2 55

2 ответа:

вы можете так же легко получить доступ к каждому элементу в списке, используя, например,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 

наткнулся на этот ответ, и я действительно хотел обе группы (данные, содержащие этого одного пользователя и данные, содержащие все, кроме этого одного пользователя). Не обязательно для специфики этого поста, но я подумал, что добавлю, если кто-то гуглил ту же проблему, что и я.

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