R 基于多个条件在销售数据中重新组合人工拆分的会话
我们有来自触摸屏自动售货机的销售数据。当客户将钱放入机器时,它会启动一个会话,使用该机器特有的数字序列对会话进行计数。大多数情况下,系统会在应该的时候启动和停止会话。然而,在大约7%的情况下,当机器中还有钱要花时,它会人工启动一个新会话 所以 其中,R 基于多个条件在销售数据中重新组合人工拆分的会话,r,data.table,R,Data.table,我们有来自触摸屏自动售货机的销售数据。当客户将钱放入机器时,它会启动一个会话,使用该机器特有的数字序列对会话进行计数。大多数情况下,系统会在应该的时候启动和停止会话。然而,在大约7%的情况下,当机器中还有钱要花时,它会人工启动一个新会话 所以 其中,可用。支出是所有不同列的总和,表示已将钱或凭证插入机器,实际支出是该会话期间花费的所有钱的总和 所以,大多数情况下,他们是平等的。然而,在第2次会议中,插入了25美元,只花了17美元。第三节课显示没有可用的钱可以花,但实际花了8美元,这就平衡了第一节
可用。支出
是所有不同列的总和,表示已将钱或凭证插入机器,实际支出
是该会话期间花费的所有钱的总和
所以,大多数情况下,他们是平等的。然而,在第2次会议中,插入了25美元,只花了17美元。第三节课显示没有可用的钱可以花,但实际花了8美元,这就平衡了第一节课
我想让R合并这些会话,并创建一个指示符列,告诉我新会话是合并会话的结果
我将如何查看会话是否平衡,如果不平衡,请检查下一个会话是否:
dput()
:
mydt<- structure(list(session = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), available.spend = c(20,
25, 0, 15, 14, 0, 59, 0, 15, 21), actual.spend = c(20, 17, 8,
15, 7, 7, 50, 9, 15, 21)), .Names = c("session", "available.spend",
"actual.spend"), row.names = c(NA, -10L), class = c("data.table",
"data.frame"), .internal.selfref = <pointer: 0x0000000000300788>)
以及dput()
:
mynew.dt所以结果与您想要的data.frame不太一样。
我在可用支出和实际支出上使用累积金额。然后我检查哪些匹配,只有那些匹配的我在new.session列中放“1”
mydt$spend.sum <-cumsum(mydt$actual.spend) #Cumulative sum of actual
mydt$avail.sum <-cumsum(mydt$available.spend) #Cumulative sum of actual
如果您的可用.expense在这些情况下始终为零,您可以使用该值对行进行分组(我假设您有时在一行中有多个0,否则您可以简单地将实际.expense
,将其移位1,然后求和以进行比较):
从这一点上,你应该有所有的信息,你需要继续
也许,更一般地说,最好按cumsum(available.spend>=actual.spend)
进行分组这是一种笨重的解决方案,但是考虑到狭窄的参数和期望的结果,我想不出更好的方法来实现这一点,除非一件一件地完成
mismatches <- mydt[available.spend != actual.spend, which=TRUE]
zeros <- mydt[available.spend == 0, which=TRUE]
x <- setdiff(mismatches, zeros)
followcheck <- mydt[x+1, session == mydt[zeros, session] & actual.spend > 0]
following.zeros <- zeros[followcheck]
sumthing <- mydt[x, available.spend==actual.spend + mydt[following.zeros, actual.spend]]
x <- x[sumthing]
y <- x + 1
mydt[x, actual.spend:=actual.spend + mydt[y, actual.spend]]
# Caution here, data.table gave a warning about needing to copy the table in memory to do this next line.
mydt[, newsess:=0]
mydt[x, newsess:=1]
mydt <- mydt[-y,]
不匹配这实际上会变得更加复杂,因为有时候,会话可能不会在下一个会话中保持平衡,而是在接下来的两个(或三个)会话中保持平衡。然而,这是非常罕见的,我希望我可以忽略这些~然而,人工创建的会话中有7%太多了,不容忽视。这当然是一个可行的解决方法。我担心的是,由于7%的会议被取消,结果会出现偏差。data.table大约有2400万行,因此7%的客户被从分析中删除。如果我不能想出上述解决方案,这将是我所能希望的最好的。谢谢你花时间来解决这个问题。再看一眼,cumsum不是好办法。只要完成最后三行代码,我就可以在可用和实际会面的地方获得会话。Cumsum使它看起来好像在数百万次中只发生了几次(前四次)。@infominer仅供参考,为了显示数据.frame
和数据.table
的可读性之间的差异,这是数据.table
方式:mydt[,new.session:=Cumsum(available.spend)==Cumsum(actual.spend)]
;或者,为了避免溢出:mydt[,new.session:=cumsum(available.spend-actual.spend)==0]
@datahappy我不明白为什么你认为cumsum
做不到你想做的事-你可能想举个例子说明它在哪里fails@eddi因为cumsum就是这样做的-提供了一个总的累积和。一旦有一个可用的和实际的不相等的实例,那么在那之后的每个实例中,它们都是不相等的。(发生在第四次观察时)。因此,当创建一个只包含完整案例的data.table时,它只包含前四个观察值,而不是它应该包含的2100万个观察值。好吧,这就像一种魅力。它正确地组合了会话,修复了所有人为分割的会话。不幸的是,它创建的data.table只包含变量session、available.spend和actual.spend(加上一个cumsum列)。如何让它保留并合并data.table中的所有其他(22)列?看起来我需要单独将所有变量添加到列表中?同样,我假设(例如totsales=sum(totsales)等)有更简单的方法来实现这一点吗?@datahappy使用.SD[1]
,而不是session=session[1]
,如果速度太慢,请参阅;或者我误解了,您想使用lappy(.SD,sum)
而不是单独的求和;你挑吧:)
mynew.dt<- structure(list(session = c(1, 2, 4, 5, 7, 9, 10), available.spend = c(20,
25, 15, 14, 59, 15, 21), actual.spend = c(20, 25, 15, 14, 59,
15, 21), newsess = c(0, 1, 0, 1, 1, 0, 0)), .Names = c("session",
"available.spend", "actual.spend", "newsess"), row.names = c(NA,
-7L), class = c("data.table", "data.frame"), .internal.selfref = <pointer: 0x0000000000300788>)
mydt$spend.sum <-cumsum(mydt$actual.spend) #Cumulative sum of actual
mydt$avail.sum <-cumsum(mydt$available.spend) #Cumulative sum of actual
mydt$new.session <-NA
mydt$new.session[with(mydt, which(spend.sum == avail.sum))]<-1
mydt[complete.cases(my.dt),]
dt[, list(session = session[1],
available.spend = sum(available.spend),
actual.spend = sum(actual.spend)),
by = cumsum(available.spend != 0)]
# cumsum session available.spend actual.spend
#1: 1 1 20 20
#2: 2 2 25 25
#3: 3 4 15 15
#4: 4 5 14 14
#5: 5 7 59 59
#6: 6 9 15 15
#7: 7 10 21 21
mismatches <- mydt[available.spend != actual.spend, which=TRUE]
zeros <- mydt[available.spend == 0, which=TRUE]
x <- setdiff(mismatches, zeros)
followcheck <- mydt[x+1, session == mydt[zeros, session] & actual.spend > 0]
following.zeros <- zeros[followcheck]
sumthing <- mydt[x, available.spend==actual.spend + mydt[following.zeros, actual.spend]]
x <- x[sumthing]
y <- x + 1
mydt[x, actual.spend:=actual.spend + mydt[y, actual.spend]]
# Caution here, data.table gave a warning about needing to copy the table in memory to do this next line.
mydt[, newsess:=0]
mydt[x, newsess:=1]
mydt <- mydt[-y,]