根据键计算多行中的标志
Count flags across multiple rows depending on key
我有一个由客户和帐户组成的数据集,其中一个客户可以有多个帐户。该数据集在每个帐户上有几个 'flags'。
我正在尝试计算每个客户对这些标志的 'unique' 次点击,即如果 3 个帐户有 flag1,我希望这算作 1 次点击,但如果只有一个帐户有 flag2我也希望这算作 2。本质上,我想看看每个客户在他们的所有帐户中点击了多少个标记。
Example Input data frame:
cust acct flag1 flag2 flag3
a 123 0 1 0
a 456 1 1 0
b 789 1 1 1
c 428 0 1 0
c 247 0 1 0
c 483 0 1 1
Example Output dataframe:
cust acct flag1 flag2 flag3 UniqueSum
a 123 0 1 0 2
a 456 1 1 0 2
b 789 1 1 1 3
c 428 0 1 0 2
c 247 0 1 0 2
c 483 0 1 1 2
我试过使用以下方法:
fSumData <- ddply(fData, "cust", numcolwise(sum, c(flag1,flag2,flag3))
但这也对 acct
列求和,为每个客户提供一行,我希望拥有与客户帐户相同的行数。
我想到的一种方法是 colSum
每个 cust
并检查哪些大于 0。例如,
> tab
cust acct flag1 flag2 flag3
1 a 123 0 1 0
2 a 456 1 1 0
3 b 789 1 1 1
4 c 428 0 1 0
5 c 247 0 1 0
6 c 483 0 1 1
> uniqueSums <- sapply(tab$cust, function(cust) length(which(colSums(tab[tab$cust == cust,3:5]) > 0)))
> cbind(tab, uniqueSums = uniqueSums)
cust acct flag1 flag2 flag3 uniqueSums
1 a 123 0 1 0 2
2 a 456 1 1 0 2
3 b 789 1 1 1 3
4 c 428 0 1 0 2
5 c 247 0 1 0 2
6 c 483 0 1 1 2
对于 cust
的每个值,sapply
中的函数查找行,进行矢量化求和并检查大于 0 的值。
这是一种使用 library(dplyr)
的方法:
df %>%
group_by(cust) %>%
summarise_each(funs(max), -acct) %>%
mutate(UniqueSum = rowSums(.[-1])) %>%
select(-starts_with("flag")) %>%
right_join(df, "cust")
#Source: local data frame [6 x 6]
#
# cust UniqueSum acct flag1 flag2 flag3
# (fctr) (dbl) (int) (int) (int) (int)
#1 a 2 123 0 1 0
#2 a 2 456 1 1 0
#3 b 3 789 1 1 1
#4 c 2 428 0 1 0
#5 c 2 247 0 1 0
#6 c 2 483 0 1 1
使用data.table
:
require(data.table) # v1.9.6
dt[, un := sum(sapply(.SD, max)), by = cust, .SDcols = flag1:flag3]
我们按 cust
分组,并在 子数据 上为每组列 flag1, flag2, flag3
(使用 .SD
和 .SDcols
),我们提取每一列的 max
,并将其相加得到 1
的总数。
我们使用 引用 使用 LHS := RHS
符号(参见 Reference Semantics 小插图)用这些值 更新原始 table。
其中 dt
是:
dt = fread('cust acct flag1 flag2 flag3
a 123 0 1 0
a 456 1 1 0
b 789 1 1 1
c 428 0 1 0
c 247 0 1 0
c 483 0 1 1')
我在阅读了 Roman 的 post 后能够回答我自己的问题,我做了类似的事情,其中 f 数据是我的数据集。
fSumData <- ddply(fData, "cust", numcolwise(sum))
fSumData$UniqueHits <- ifelse(fSumData$flag1 >= 1;1,0) + ifelse(fSumData$flag2 >= 1;1;0) + ifelse(fSumData$flag3 >= 1;1;0)
当 运行 针对我的数据集时,我发现这比 Roman 的解决方案快一点,但我不确定它是否是最佳解决方案。谢谢大家的意见,这帮了大忙!
未充分利用的 rowsum
也可能有用:
rowSums(rowsum(DF[-(1:2)], DF$cust) > 0)[DF$cust]
#a a b c c c
#2 2 3 2 2 2
我有一个由客户和帐户组成的数据集,其中一个客户可以有多个帐户。该数据集在每个帐户上有几个 'flags'。
我正在尝试计算每个客户对这些标志的 'unique' 次点击,即如果 3 个帐户有 flag1,我希望这算作 1 次点击,但如果只有一个帐户有 flag2我也希望这算作 2。本质上,我想看看每个客户在他们的所有帐户中点击了多少个标记。
Example Input data frame:
cust acct flag1 flag2 flag3
a 123 0 1 0
a 456 1 1 0
b 789 1 1 1
c 428 0 1 0
c 247 0 1 0
c 483 0 1 1
Example Output dataframe:
cust acct flag1 flag2 flag3 UniqueSum
a 123 0 1 0 2
a 456 1 1 0 2
b 789 1 1 1 3
c 428 0 1 0 2
c 247 0 1 0 2
c 483 0 1 1 2
我试过使用以下方法:
fSumData <- ddply(fData, "cust", numcolwise(sum, c(flag1,flag2,flag3))
但这也对 acct
列求和,为每个客户提供一行,我希望拥有与客户帐户相同的行数。
我想到的一种方法是 colSum
每个 cust
并检查哪些大于 0。例如,
> tab
cust acct flag1 flag2 flag3
1 a 123 0 1 0
2 a 456 1 1 0
3 b 789 1 1 1
4 c 428 0 1 0
5 c 247 0 1 0
6 c 483 0 1 1
> uniqueSums <- sapply(tab$cust, function(cust) length(which(colSums(tab[tab$cust == cust,3:5]) > 0)))
> cbind(tab, uniqueSums = uniqueSums)
cust acct flag1 flag2 flag3 uniqueSums
1 a 123 0 1 0 2
2 a 456 1 1 0 2
3 b 789 1 1 1 3
4 c 428 0 1 0 2
5 c 247 0 1 0 2
6 c 483 0 1 1 2
对于 cust
的每个值,sapply
中的函数查找行,进行矢量化求和并检查大于 0 的值。
这是一种使用 library(dplyr)
的方法:
df %>%
group_by(cust) %>%
summarise_each(funs(max), -acct) %>%
mutate(UniqueSum = rowSums(.[-1])) %>%
select(-starts_with("flag")) %>%
right_join(df, "cust")
#Source: local data frame [6 x 6]
#
# cust UniqueSum acct flag1 flag2 flag3
# (fctr) (dbl) (int) (int) (int) (int)
#1 a 2 123 0 1 0
#2 a 2 456 1 1 0
#3 b 3 789 1 1 1
#4 c 2 428 0 1 0
#5 c 2 247 0 1 0
#6 c 2 483 0 1 1
使用data.table
:
require(data.table) # v1.9.6
dt[, un := sum(sapply(.SD, max)), by = cust, .SDcols = flag1:flag3]
我们按 cust
分组,并在 子数据 上为每组列 flag1, flag2, flag3
(使用 .SD
和 .SDcols
),我们提取每一列的 max
,并将其相加得到 1
的总数。
我们使用 引用 使用 LHS := RHS
符号(参见 Reference Semantics 小插图)用这些值 更新原始 table。
其中 dt
是:
dt = fread('cust acct flag1 flag2 flag3
a 123 0 1 0
a 456 1 1 0
b 789 1 1 1
c 428 0 1 0
c 247 0 1 0
c 483 0 1 1')
我在阅读了 Roman 的 post 后能够回答我自己的问题,我做了类似的事情,其中 f 数据是我的数据集。
fSumData <- ddply(fData, "cust", numcolwise(sum))
fSumData$UniqueHits <- ifelse(fSumData$flag1 >= 1;1,0) + ifelse(fSumData$flag2 >= 1;1;0) + ifelse(fSumData$flag3 >= 1;1;0)
当 运行 针对我的数据集时,我发现这比 Roman 的解决方案快一点,但我不确定它是否是最佳解决方案。谢谢大家的意见,这帮了大忙!
未充分利用的 rowsum
也可能有用:
rowSums(rowsum(DF[-(1:2)], DF$cust) > 0)[DF$cust]
#a a b c c c
#2 2 3 2 2 2