R 编程 - 有条件地将函数应用于按组排序的大型数据帧



我有一个非常大的数据框(~800K 行),按 CustomerID、最早事务 {"日期"} 和 Sales 排序,如下所示......

CustomerID    Date          Sales
AAA123        1-01-2015     49.00
AAA123        1-02-2015     24.00
AAA123        1-03-2015     17.00
BBB456        2-01-2015     117.00
CCC789        1-01-2012     65.20
CCC789        12-12-2012    43.00

正在尝试有条件地聚合此 data.frame,这样我只想为每个显示他/她最早重复交易的"客户"获取一行(即,如果他们有多个行用于该"CustomerID",则为上表中的第二笔交易),除非该"客户"只有一笔交易, 在这种情况下,我希望"客户"的唯一交易在我的结果中显示为他们的"最早"交易条目。所以从本质上讲,我生成的 data.frame 看起来像这样:

CustomerID    Date          Sales
AAA123        1-01-2015     49.00
BBB456        2-01-2015     117.00
CCC789        1-01-2012     65.20

我试过使用

results <- do.call(rbind,by(old_data,old_data$CustomerID,function(x) x[-1,]))

但不幸的是,我无法让它按照我想要的方式工作。相反,它会删除那些只有一笔交易的"客户"。有谁知道一种方法可以有条件地应用像"do.call"这样快速、高效且易于应用的函数?

对于大型数据集,data.table可以有效地使用。 我们将"data.frame"转换为"data.table"(setDT(df1)),按"CustomerID"分组,我们得到最小"日期"的索引并子集数据集行。

library(data.table)
library(lubridate)
setDT(df1)[, .SD[which.min(mdy(Date))] , by = CustomerID]
#    CustomerID      Date Sales
# 1:     AAA123 1-01-2015  49.0
# 2:     BBB456 2-01-2015 117.0
# 3:     CCC789 1-01-2012  65.2

或者我们在与"CustomerID"分组后按"日期"order,然后得到Data.table子集的第一个元素(.SD)。

setDT(df1)[order(mdy(Date)), head(.SD, 1L) , by =  CustomerID]

以上是根据OP显示的预期产出计算的。 但是,根据描述,这是需要的第二笔交易,在这种情况下,我们可能需要一个条件

setDT(df1)[order(mdy(Date)), if(.N==1) .SD else .SD[2L], 
                            by = CustomerID]

试试这个(其中"df"是数据框的名称):

df <- df[order(df$CustomerID, df$Date),] 
df <- df[!duplicated(df$CustomerID),]

第一行按 CustomerID 对数据框进行排序,然后按日期顺序对每个客户的交易进行排序。 order() 函数的默认值是按递增顺序排序,以便每个客户的交易将按最早到最新的顺序列出。

第二行删除具有重复 CustomerID 的所有行 - 留下每个客户的第一个(或唯一)事务。

最新更新