2014-10-12 5 views
0

Я новичок в r, и мне нужно подсчитать значения в столбце, разделенном «:».Считать значения в столбцах, разделенных символом «:»

В наборе данных есть 4 категории, и мне приходится подсчитывать количество действий для каждой категории. Каждый log_id представляет собой уникальное действие в категории. Если для одного log_id есть 2 или более категории, это означает, что это конкретное действие будет учитываться во всех упомянутых категориях.

Данные выглядят как этот

user_id log_id categories 
    001  1334 Perform:Sport_Well:Com.Tent 
    001  1323 Com.Tent 
    001  1212 Active 
    002  1113 NA 
    002  1478 Com.Tent:Active 
    002  1134 Sport_Well:Perform 
    002  1256 Perform 
    002  1590 Perform 
    002  1345 NA 
    002  1478 Com.Tent 
    002  1134 Sport_Well:Perform 
    002  1256 Perform 
    003  1590 Perform 
    003  1345 Active:Perform 
    003  1190 Perform:Com.Tent 
    003  1239 Active:Perform 

Вот dput:

dat <- structure(list(user_id = c("001", "001", "001", "002", "002", 
    "002", "002", "002", "002", "002", "002", "002", "003", "003", 
    "003", "003"), log_id = c("1334", "1323", "1212", "1113", "1478", 
    "1134", "1256", "1590", "1345", "1478", "1134", "1256", "1590", 
    "1345", "1190", "1239"), categories = c("Perform:Sport_Well:Com.Tent", 
    "Com.Tent", "Active", NA, "Com.Tent:Active", "Sport_Well:Perform", 
    "Perform", "Perform", NA, "Com.Tent", "Sport_Well:Perform", "Perform", 
    "Perform", "Active:Perform", "Perform:Com.Tent", "Active:Perform")), 
    .Names = c("user_id", "log_id", "categories"), class = "data.frame", row.names = c(NA, -16L)) 

Нужный выход ниже:

user_id category  NumActions 
    001  Perform    1 
    001  Sport_Well   1 
    001  Com.Tent   2 
    001  Active    1 
    002  Com.Tent   2 
    002  Active    1 
    002  Perform    5 
    002  Sport_Well   2 
    003  Com.Tent   2 
    003  Active    2 
    003  Perform    4 

Я пытаюсь разделить категории, но не могу понять как подсчитывать log_ids с несколькими категориями.

df$cate = str_split(string = df$Ch_Category, pattern = ":") 

ответ

1

После базового R код дает тот же результат, но в другом формате:

> aa = aggregate(categories~user_id, data=dat, function(x) paste(x,collapse=':')) 
> sapply(sapply(split(aa, aa$user_id), function(x) strsplit(x$categories, ':') ), table) 
$`001` 

    Active Com.Tent Perform Sport_Well 
     1   2   1   1 

$`002` 

    Active Com.Tent Perform Sport_Well 
     1   2   5   2 

$`003` 

    Active Com.Tent Perform 
     2  1  4 
+0

Спасибо @mso, но мне нужно объединить отдельные категории. –

+0

Я отредактировал свой ответ выше. – rnso

2

Разделить строки в столбце, добавить в виде строк во временный фрейм данных, а затем выполнить подсчет. В этом примере используется dplyr идиомы, но я уверен, что другие будут размещать базы R решения, если вы не можете использовать dplyr:

library(dplyr) 

cats <- strsplit(dat$categories, ":") 
tmp <- data.frame(user_id = rep(dat$user_id, sapply(cats, length)), categories = unlist(cats)) 
tmp %>% 
    group_by(user_id, categories) %>% 
    summarise(NumActions=n()) %>% 
    ungroup 

## user_id categories NumActions 
## 1  001  Active   1 
## 2  001 Com.Tent   2 
## 3  001 Perform   1 
## 4  001 Sport_Well   1 
## 5  002  Active   1 
## 6  002 Com.Tent   2 
## 7  002 Perform   5 
## 8  002 Sport_Well   2 
## 9  002   NA   2 
## 10  003  Active   2 
## 11  003 Com.Tent   1 
## 12  003 Perform   4 
3

dplyr Вот dplyr решение:

library(dplyr) 

dat %>% 
    group_by(user_id) %>% 
    do(strsplit(.$categories, ":") %>% 
     unlist %>% 
     table(dnn = "category") %>% 
     as.data.frame(responseName = "numActions", stringsAsFactors = FALSE)) 

, который дает :

Source: local data frame [11 x 3] 
Groups: user_id 

    user_id categories numActions 
1  001  Active   1 
2  001 Com.Tent   2 
3  001 Perform   1 
4  001 Sport_Well   1 
5  002  Active   1 
6  002 Com.Tent   2 
7  002 Perform   5 
8  002 Sport_Well   2 
9  003  Active   2 
10  003 Com.Tent   1 
11  003 Perform   4 

Обратите внимание, что если вы не заботитесь об именах заголовка, то мы можем опустить dnn=... и responseName=... и если предупреждение, которое может быть проигнорировано в порядке, то мы можем опустить stringsAsFactors=... так с этими оговорками может быть сокращен до:

dat %>% 
    group_by(user_id) %>% 
    do(strsplit(.$categories, ":") %>% unlist %>% table %>% as.data.frame) 

data.table Это может быть сделано так же в data.table:

library(data.table) 
DT <- data.table(dat) 
DT[, as.data.frame(table(unlist(strsplit(categories, ":")), dnn = "categories"), 
       responseName = "numActions"), by = user_id] 

и укороченный последнее утверждение с той оговоркой, что имена столбцов не являются одинаковыми:

DT[, as.data.frame(table(unlist(strsplit(categories, ":")))), by = user_id] 
+0

Большое спасибо за помощь. Поскольку я новичок в R, я не понимаю «%>%». Я буду признателен, если вы сможете кратко объяснить, как работает этот код. –

+0

Прочитайте виньетку с пакетом magrittr. –

2

Я играл вокруг с tidyr сегодня, так вот решение, использующее этот пакет.

Первый I separate объединенная колонка на три. Я переформатирую полученный набор данных в длинный формат с gather (удаление отсутствующих значений). Затем я добавляю номера для каждой группы, используя dplyrgroup_by и summarise.

library(tidyr) 
library(dplyr) 

Раздельное один столбец на три:

dat %>% 
    separate(categories, c("a", "b", "c"), sep = ":", extra = "merge") 

    user_id log_id   a   b  c 
1  001 1334 Perform Sport_Well Com.Tent 
2  001 1323 Com.Tent  <NA>  <NA> 
3  001 1212  Active  <NA>  <NA> 
4  002 1113  <NA>  <NA>  <NA> 
5  002 1478 Com.Tent  Active  <NA> 
6  002 1134 Sport_Well Perform  <NA> 
7  002 1256 Perform  <NA>  <NA> 
8  002 1590 Perform  <NA>  <NA> 
9  002 1345  <NA>  <NA>  <NA> 
10  002 1478 Com.Tent  <NA>  <NA> 
11  002 1134 Sport_Well Perform  <NA> 
12  002 1256 Perform  <NA>  <NA> 
13  003 1590 Perform  <NA>  <NA> 
14  003 1345  Active Perform  <NA> 
15  003 1190 Perform Com.Tent  <NA> 
16  003 1239  Active Perform  <NA> 

сделать в длинном формате (один столбец для категории):

dat %>% 
    separate(categories, c("a", "b", "c"), sep = ":", extra = "merge") %>% 
    gather(variable, category, a:c, na.rm = TRUE) 

    user_id log_id variable category 
1  001 1334  a Perform 
2  001 1323  a Com.Tent 
3  001 1212  a  Active 
4  002 1478  a Com.Tent 
5  002 1134  a Sport_Well 
6  002 1256  a Perform 
7  002 1590  a Perform 
... 

А потом группа по user_id и category и подсчитать число в каждая группа.

dat %>% 
separate(categories, c("a", "b", "c"), sep = ":", extra = "merge") %>% 
gather(variable, category, a:c, na.rm = TRUE) %>% 
group_by(user_id, category) %>% 
summarise(NumActions = n()) 

    user_id category NumActions 
1  001  Active   1 
2  001 Com.Tent   2 
3  001 Perform   1 
4  001 Sport_Well   1 
5  002  Active   1 
6  002 Com.Tent   2 
7  002 Perform   5 
8  002 Sport_Well   2 
9  003  Active   2 
10  003 Com.Tent   1 
11  003 Perform   4 
1

Вы можете использовать my cSplit function вместе с .N из "data.table", как это:

cSplit(dat, "categories", ":", "long")[, list(NumActions = .N), 
             by = list(user_id, categories)] 
#  user_id categories NumActions 
# 1:  001 Perform   1 
# 2:  001 Sport_Well   1 
# 3:  001 Com.Tent   2 
# 4:  001  Active   1 
# 5:  002   NA   2 
# 6:  002 Com.Tent   2 
# 7:  002  Active   1 
# 8:  002 Sport_Well   2 
# 9:  002 Perform   5 
# 10:  003 Perform   4 
# 11:  003  Active   2 
# 12:  003 Com.Tent   1 

Обратите внимание, что это также считается NA, которые вы можете или не хотите. Если вы этого не хотите. Простой na.omit - это все, что потребуется для удаления этих значений. Чтобы удалить NA «категории», просто добавьте следующее в конец указанной команды:

[!is.na(categories)] 
Смежные вопросы