Разделить большой фрейм данных в список фреймов данных на основе общего значения в столбце
У меня есть кадр данных с 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], например.
При применении на исходном большом кадре данных или даже в представлении матрицы это забивает мою машину (4 ГБ ОЗУ, MacOSX 10.6, R 2.15) и никогда не завершается (я знаю, что существует более новая версия R, но я считаю, что это не Главная проблема).
Кажется, что split более совершенен и после долгого времени завершается, но я не знаю (низшего знания R), как вырезать результирующий список векторов в вектор матриц.
path = split(smallsampleMat, smallsampleMat[,10])
Я также рассмотрел использование big.matrix
и т.д., но без особого успеха, что ускорит процесс.
Ответы
Ответ 1
Вы можете так же легко получить доступ к каждому элементу в списке, используя, например, 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
Наткнулся на этот ответ, и я действительно хотел ОБА группы (данные, содержащие этого одного пользователя и данные, содержащие все, кроме этого одного пользователя). Не обязательно для специфики этого поста, но я подумал, что добавлю, если кто-то будет гуглить ту же проблему, что и я.
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
Ответ 3
Начиная с версии 0.8.0, dplyr
предлагает 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)