使用dplyr将一个data.frame输出到另一个data.frame
我有两个data.frames——一个查找表,告诉我一组中包含的一组产品。每组至少有一种1型和2型产品 第二个data.frame告诉我有关事务的详细信息。每笔交易可以有以下产品之一: a) 仅来自其中一组的类型1产品s b) 仅来自其中一组的2型产品s c) 同一组的1型和2型产品 对于我的分析,我感兴趣的是找出上面的c),即类型1和类型2(来自同一组)的产品销售了多少笔交易。如果在同一笔交易中销售的不同组的1类和2类产品,我们将完全忽略该交易 因此,类型1或类型2的每个产品必须属于同一组 这是我的查找表:使用dplyr将一个data.frame输出到另一个data.frame,r,nested,dplyr,R,Nested,Dplyr,我有两个data.frames——一个查找表,告诉我一组中包含的一组产品。每组至少有一种1型和2型产品 第二个data.frame告诉我有关事务的详细信息。每笔交易可以有以下产品之一: a) 仅来自其中一组的类型1产品s b) 仅来自其中一组的2型产品s c) 同一组的1型和2型产品 对于我的分析,我感兴趣的是找出上面的c),即类型1和类型2(来自同一组)的产品销售了多少笔交易。如果在同一笔交易中销售的不同组的1类和2类产品,我们将完全忽略该交易 因此,类型1或类型2的每个产品必须属于同一组 这
> P_Lookup
Group ProductID1 ProductID2
Group1 A 1
Group1 B 2
Group1 B 3
Group2 C 4
Group2 C 5
Group2 C 6
Group3 D 7
Group3 C 8
Group3 C 9
Group4 E 10
Group4 F 11
Group4 G 12
Group5 H 13
Group5 H 14
Group5 H 15
例如,我不会在一个事务中包含产品G和产品15,因为它们属于不同的组
以下是交易记录:
TransactionID ProductID ProductType
a1 A 1
a1 B 1
a1 1 2
a2 C 1
a2 4 2
a2 5 2
a3 D 1
a3 C 1
a3 7 2
a3 8 2
a4 H 1
a5 1 2
a5 2 2
a5 3 2
a5 3 2
a5 1 2
a6 H 1
a6 15 2
我的代码:
现在,我能够使用dplyr
为一个组的入围交易编写代码。但是,我不确定如何为所有组矢量化我的代码
这是我的密码:
P_Groups<-unique(P_Lookup$Group)
Chosen_Group<-P_Groups[5]
P_Group_Ind <- P_Trans %>%
group_by(TransactionID)%>%
dplyr::filter((ProductID %in% unique(P_Lookup[P_Lookup$Group==Chosen_Group,]$ProductID1)) |
(ProductID %in% unique(P_Lookup[P_Lookup$Group==Chosen_Group,]$ProductID2)) ) %>%
mutate(No_of_PIDs = n_distinct(ProductType)) %>%
mutate(Group_Name = Chosen_Group)
P_Group_Ind<-P_Group_Ind[P_Group_Ind$No_of_PIDs>1,]
以下是p\u查找的dput
:
structure(list(Group = c("Group1", "Group1", "Group1", "Group2",
"Group2", "Group2", "Group3", "Group3", "Group3", "Group4", "Group4",
"Group4", "Group5", "Group5", "Group5"), ProductID1 = c("A",
"B", "B", "C", "C", "C", "D", "C", "C", "E", "F", "G", "H", "H",
"H"), ProductID2 = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
14, 15)), .Names = c("Group", "ProductID1", "ProductID2"), row.names = c(NA,
15L), class = "data.frame")
以下是将查找表中不存在的产品添加到p_Trans后的dput()
:
> P_Lookup
Group ProductID1 ProductID2
Group1 A 1
Group1 B 2
Group1 B 3
Group2 C 4
Group2 C 5
Group2 C 6
Group3 D 7
Group3 C 8
Group3 C 9
Group4 E 10
Group4 F 11
Group4 G 12
Group5 H 13
Group5 H 14
Group5 H 15
structure(list(TransactionID = c("a1", "a1", "a1", "a2", "a2",
"a2", "a3", "a3", "a3", "a3", "a4", "a5", "a5", "a5", "a5", "a5",
"a6", "a6", "a7"), ProductID = c("A", "B", "1", "C", "4", "5",
"D", "C", "7", "8", "H", "1", "2", "3", "3", "1", "H", "15",
"22"), ProductType = c(1, 1, 2, 1, 2, 2, 1, 1, 2, 2, 1, 2, 2,
2, 2, 2, 1, 2, 3)), .Names = c("TransactionID", "ProductID",
"ProductType"), row.names = c(NA, 19L), class = "data.frame")
下面是一个tidyverse(dplyr、tidyr和purrr)解决方案,我希望能有所帮助
请注意,在最后一行中使用map_df
会将所有结果作为数据帧返回。如果您希望它成为每个组的列表对象,那么只需使用map
library(dplyr)
library(tidyr)
library(purrr)
# Save unique groups for later use
P_Groups <- unique(P_Lookup$Group)
# Convert lookup table to product IDs and Groups
P_Lookup <- P_Lookup %>%
gather(ProductIDn, ProductID, ProductID1, ProductID2) %>%
select(ProductID, Group) %>%
distinct() %>%
nest(-ProductID, .key = Group)
# Bind Group information to transactions
# and group for next analysis
P_Trans <- P_Trans %>%
left_join(P_Lookup) %>%
filter(!map_lgl(Group, is.null)) %>%
unnest(Group) %>%
group_by(TransactionID)
# Iterate through Groups to produce results
map(P_Groups, ~ filter(P_Trans, Group == .)) %>%
map(~ mutate(., No_of_PIDs = n_distinct(ProductType))) %>%
map_df(~ filter(., No_of_PIDs > 1))
#> Source: local data frame [12 x 5]
#> Groups: TransactionID [4]
#>
#> TransactionID ProductID ProductType Group No_of_PIDs
#> <chr> <chr> <dbl> <chr> <int>
#> 1 a1 A 1 Group1 2
#> 2 a1 B 1 Group1 2
#> 3 a1 1 2 Group1 2
#> 4 a2 C 1 Group2 2
#> 5 a2 4 2 Group2 2
#> 6 a2 5 2 Group2 2
#> 7 a3 D 1 Group3 2
#> 8 a3 C 1 Group3 2
#> 9 a3 7 2 Group3 2
#> 10 a3 8 2 Group3 2
#> 11 a6 H 1 Group5 2
#> 12 a6 15 2 Group5 2
库(dplyr)
图书馆(tidyr)
图书馆(purrr)
#保存唯一组以供以后使用
P_组%
选择(产品ID,组)%>%
不同的()%>%
嵌套(-ProductID,.key=Group)
#将组信息绑定到事务
#并分组进行下一步分析
P_Trans%
左联合(P\U查找)%>%
筛选器(!map_lgl(组,is.null))%>%
unnest(组)%%>%
分组人(交易ID)
#遍历组以生成结果
映射(P_组,~filter(P_Trans,Group==)%>%
映射(~变异(,PIDs的编号=n不同(ProductType))%>%
map_df(~过滤器(,PIDs数量>1))
#>来源:本地数据帧[12 x 5]
#>组:TransactionID[4]
#>
#>TransactionID ProductID ProductType组编号为
#>
#>1 a1 A 1组1 2
#>2 a1 B 1组1 2
#>3 a1 1 2组1 2
#>4 a2 C1组2 2
#>5 a2 4 2组2 2
#>6 a2 5 2组2 2
#>7 a3 D 1组3 2
#>8 a3 C1组3 2
#>9 a3 7 2组3 2
#>10 a3 8 2组3 2
#>11 a6 H 1组5 2
#>12 a6 15 2组5 2
这里有一个单管dplyr
解决方案:
P_DualGroupTransactionsCount <-
P_Lookup %>% # data needing single column map of Keys
gather(IDnum, ProductID, ProductID1:ProductID2) %>% # produce long single map of Keys for GroupID (tidyr::)
right_join(P_trans) %>% # join transactions to groupID info
group_by(TransactionID, Group) %>% # organize for same transaction & same group
mutate(DualGroup = ifelse(n_distinct(ProductType)==2, T, F)) %>% # flag groups with both groups in a single transaction
filter(DualGroup == T) %>% # choose only doubles
select(TransactionID, Group) %>% # remove excess columns
distinct %>% # remove excess rows
nrow # count of unique transaction ID's
# P_DualGroupTransactions
# Source: local data frame [4 x 2]
# Groups: TransactionID, Group [4]
#
# TransactionID Group
# <chr> <chr>
# 1 a1 Group1
# 2 a2 Group2
# 3 a3 Group3
# 4 a6 Group5
# P_DualGroupTransactionsCount
[1] 4
P_DualGroupTransactionCount%#需要单列键映射的数据
聚集(IDnum、ProductID、ProductID1:ProductID2)%>%#为GroupID(tidyr::)生成键的长单映射
右键连接(P_trans)%>%#将事务连接到groupID信息
分组依据(TransactionID,group)%>%#为同一事务和同一组组织
mutate(DualGroup=ifelse(n_distinct(ProductType)==2,T,F))%>%#在单个事务中标记两个组的组
过滤器(双组==T)%>%#仅选择双组
选择(TransactionID,组)%>%#删除多余的列
独特%>%#删除多余的行
nrow#唯一事务ID的计数
#P_DualGroupTransactions
#来源:本地数据帧[4 x 2]
#组:TransactionID,组[4]
#
#事务ID组
#
#1 a1组1
#2 a2组2
#3 a3组3
#4 a6组5
#P_DualGroupTransactionCount
[1] 4
这是一个极好的回答。我是一个初学者,所以我有一个简单的问题:你能解释一下为什么你做了变异(I=1:n())
和as\u data\u frame()
。我试着在没有这两行代码的情况下运行代码,效果很好。所以,我很好奇。好的,抓住了望塔!那些台词只是在我前进的过程中帮我把事情弄清楚。我已经从答案中删除了它们。谢谢你的澄清。我有一个简单的问题——我的原始数据集P_Trans
有一些ProductID
s,它们不在查找表P_Lookup
中。在这种情况下,我得到了这个错误:每一列必须是向量列表或数据帧列表[Group]
。我是一个初学者,所以我不知道如何解决这个问题。你能帮我吗?根据SO的策略,我不想创建新线程。我在帖子中添加了dput()
。我衷心感谢你的帮助help@watchtower谢谢你的接受。我做了一个更改,将删除未包含在查找表中的所有产品:过滤器(!map\u lgl(Group,is.null))
。这在绑定到P\u Trans
时发生。