使用 Tidyr/Dplyr 来汇总字符串组的计数
Using Tidyr/Dplyr to summarise counts of groups of strings
我需要总结分配给组的字符串的数量,我知道我可以在 dplyr/tidyr 中完成,但我遗漏了一些东西。
示例数据集:
Owner = c('bob','julia','cheryl','bob','julia','cheryl')
Day = c('Mon', 'Tue')
Locn = c('house','store','apartment','office','house','shop')
data <- data.frame(Owner, Day, Locn)
看起来像这样:
Owner Day Locn
1 bob Mon house
2 julia Tue store
3 cheryl Mon apartment
4 bob Tue office
5 julia Mon house
6 cheryl Tue shop
我想按名称和日期分组,然后在列中计算分组位置。在此示例中,我希望将 'house' 和 'apartment' 添加到标题为 'Home' 的列中,并将 'store'、'office' 和 'shop' 计入一列 'Work'.
我当前的代码(不起作用):
grouped_locn <- data %>%
dplyr::arrange(Owner, Day) %>%
dplyr::group_by(Owner, Day) %>%
dplyr::summarize(Home = which(data$Locn %in% c('house', 'apartment')),
Work = which(data$Locn %in% c("store", "office", "apartment")))
我只在总结步骤中包含了我目前的尝试,以展示我是如何接近它的。当前的家庭和工作代码 returns 包含组元素的行号向量(即 Home = 1 3 5)
我的预期输出:
Owner Day Home Work
1 bob Mon 1 0
2 bob Tue 0 1
3 julia Mon 1 0
4 julia Tue 0 1
5 cheryl Mon 1 0
6 cheryl Tue 0 1
在实际数据集(30k+ 行)中,每个所有者每天有多个 Locn 值,因此家庭和工作计数可以是 1 和 0 以外的数字(因此没有布尔值)。
非常感谢。
这是一个使用 data.table
的简单高效的解决方案
对于旧版本 (v < 1.9.5)
library(data.table) # v < 1.9.5
setDT(data)[, Locn2 := c("Work", "Home")[(Locn %in% c('house', 'apartment')) + 1L]]
dcast.data.table(data, Owner + Day ~ Locn2, length)
# Owner Day Home Work
# 1: bob Mon 1 0
# 2: bob Tue 0 1
# 3: cheryl Mon 1 0
# 4: cheryl Tue 0 1
# 5: julia Mon 1 0
# 6: julia Tue 0 1
对于较新的版本 (v >= 1.9.5),您可以在一行中完成此操作
dcast(setDT(data), Owner + Day ~ c("Work", "Home")[(Locn %in% c('house', 'apartment')) + 1L], length)
这里有一个 tidyr
替代方案
library(dplyr)
library(tidyr)
data %>%
mutate(temp = 1L,
Locn = ifelse(Locn %in% c('house', 'apartment'), "Home", "Work")) %>%
spread(Locn, temp, fill = 0L)
# Owner Day Home Work
# 1 bob Mon 1 0
# 2 bob Tue 0 1
# 3 cheryl Mon 1 0
# 4 cheryl Tue 0 1
# 5 julia Mon 1 0
# 6 julia Tue 0 1
试试这个
data %>%
group_by(Owner, Day) %>%
summarise(Home = sum(Locn %in% c("house", "apartment")),
Work = sum(Locn %in% c("store", "office", "shop")))
这就像@lukeA 提出的解决方案,但使用 grepl
函数:
library(dplyr)
data %<>% arrange(Owner, Day) %>% group_by(Owner, Day) %>%
summarise(Home=sum((grepl("house|apartment", Locn))*1),
Work=sum((grepl("store|office|shop", Locn))*1))
您可以使用 model.matrix
来自 base R
data[c('Work', 'Home')] <- model.matrix(~0+indx, transform(data,
indx = Locn %in% c('house', 'apartment')))
data
# Owner Day Locn Work Home
#1 bob Mon house 0 1
#2 julia Tue store 1 0
#3 cheryl Mon apartment 0 1
#4 bob Tue office 1 0
#5 julia Mon house 0 1
#6 cheryl Tue shop 1 0
或
library(qdapTools)
data[c('Work', 'Home')] <- mtabulate(data$Locn %in% c('house', 'apartment'))
我需要总结分配给组的字符串的数量,我知道我可以在 dplyr/tidyr 中完成,但我遗漏了一些东西。
示例数据集:
Owner = c('bob','julia','cheryl','bob','julia','cheryl')
Day = c('Mon', 'Tue')
Locn = c('house','store','apartment','office','house','shop')
data <- data.frame(Owner, Day, Locn)
看起来像这样:
Owner Day Locn
1 bob Mon house
2 julia Tue store
3 cheryl Mon apartment
4 bob Tue office
5 julia Mon house
6 cheryl Tue shop
我想按名称和日期分组,然后在列中计算分组位置。在此示例中,我希望将 'house' 和 'apartment' 添加到标题为 'Home' 的列中,并将 'store'、'office' 和 'shop' 计入一列 'Work'.
我当前的代码(不起作用):
grouped_locn <- data %>%
dplyr::arrange(Owner, Day) %>%
dplyr::group_by(Owner, Day) %>%
dplyr::summarize(Home = which(data$Locn %in% c('house', 'apartment')),
Work = which(data$Locn %in% c("store", "office", "apartment")))
我只在总结步骤中包含了我目前的尝试,以展示我是如何接近它的。当前的家庭和工作代码 returns 包含组元素的行号向量(即 Home = 1 3 5)
我的预期输出:
Owner Day Home Work
1 bob Mon 1 0
2 bob Tue 0 1
3 julia Mon 1 0
4 julia Tue 0 1
5 cheryl Mon 1 0
6 cheryl Tue 0 1
在实际数据集(30k+ 行)中,每个所有者每天有多个 Locn 值,因此家庭和工作计数可以是 1 和 0 以外的数字(因此没有布尔值)。
非常感谢。
这是一个使用 data.table
对于旧版本 (v < 1.9.5)
library(data.table) # v < 1.9.5
setDT(data)[, Locn2 := c("Work", "Home")[(Locn %in% c('house', 'apartment')) + 1L]]
dcast.data.table(data, Owner + Day ~ Locn2, length)
# Owner Day Home Work
# 1: bob Mon 1 0
# 2: bob Tue 0 1
# 3: cheryl Mon 1 0
# 4: cheryl Tue 0 1
# 5: julia Mon 1 0
# 6: julia Tue 0 1
对于较新的版本 (v >= 1.9.5),您可以在一行中完成此操作
dcast(setDT(data), Owner + Day ~ c("Work", "Home")[(Locn %in% c('house', 'apartment')) + 1L], length)
这里有一个 tidyr
替代方案
library(dplyr)
library(tidyr)
data %>%
mutate(temp = 1L,
Locn = ifelse(Locn %in% c('house', 'apartment'), "Home", "Work")) %>%
spread(Locn, temp, fill = 0L)
# Owner Day Home Work
# 1 bob Mon 1 0
# 2 bob Tue 0 1
# 3 cheryl Mon 1 0
# 4 cheryl Tue 0 1
# 5 julia Mon 1 0
# 6 julia Tue 0 1
试试这个
data %>%
group_by(Owner, Day) %>%
summarise(Home = sum(Locn %in% c("house", "apartment")),
Work = sum(Locn %in% c("store", "office", "shop")))
这就像@lukeA 提出的解决方案,但使用 grepl
函数:
library(dplyr)
data %<>% arrange(Owner, Day) %>% group_by(Owner, Day) %>%
summarise(Home=sum((grepl("house|apartment", Locn))*1),
Work=sum((grepl("store|office|shop", Locn))*1))
您可以使用 model.matrix
来自 base R
data[c('Work', 'Home')] <- model.matrix(~0+indx, transform(data,
indx = Locn %in% c('house', 'apartment')))
data
# Owner Day Locn Work Home
#1 bob Mon house 0 1
#2 julia Tue store 1 0
#3 cheryl Mon apartment 0 1
#4 bob Tue office 1 0
#5 julia Mon house 0 1
#6 cheryl Tue shop 1 0
或
library(qdapTools)
data[c('Work', 'Home')] <- mtabulate(data$Locn %in% c('house', 'apartment'))