我有一个垂直排列(堆叠)的汇集时间序列data.frame
,如下所示:
date item qty_sold
day_1 orange 0
day_2 orange 0
day_3 orange 0
day_4 orange 0
day_5 orange 5
day_6 orange 0
day_7 orange 8
day_8 orange 0
day_1 hammer 0
day_2 hammer 0
day_3 hammer 3
day_4 hammer 0
day_5 hammer 70
day_6 hammer 70
day_7 hammer 0
Day_8 hammer 80
在每个“项目”的子系列/子组中,我需要在观察到第一个正qty_sold的那天之前识别并删除所有观察*。例如,对于“ orange ”系列,这意味着要确定第1天到第4天,对于“锤”系列,这意味着要在前2天内完成。
(如果上述说明不清楚): 从数据集中的每个子系列,我需要删除从date = Day_1到date = Day_k的所有日期,这样对于区间1 ... k qty_sold = 0中的每一天,AND保留所有日期的行= Day_k + 1 qty_sold> = 0)
有人可以就如何解决这个问题提出一个想法吗?实际数据集包含大约一百万行。我也欢迎使用SAS除R之外的建议。
答案 0 :(得分:3)
我完全赞同@joran在那里的观点。我会在这里给出(n)(R)答案,即使这个问题没有显示出任何研究成果。对于未来,请向我们展示您尝试过的代码。
对于您的问题,第一步是使用基本功能或一个很好的包,它可以帮助您split
data.frame
组apply
,combine
您想要的任何功能应用于每个拆分组并split-apply-combine
结果(通常称为plyr
策略)。有几个不错的(外部)包,即data.table
和data.table
。虽然,我更喜欢data.frame
data.frame
- 类似操作,因为它通常要快得多。
首先,我们会将您的data.table
转换为install.packages("data.table")
。如果您没有安装此软件包,则可以执行require(data.table) # load package
dt <- data.table(df) # convert data.frame to data.table
。
data.table
现在,要将by
拆分成组,我们可以在data.table
中使用参数apply
。我们的cummax
函数将为dt[, .SD[cummax(qty_sold) > 0], by = item]
item date qty_sold
1: orange day_5 5
2: orange day_6 0
3: orange day_7 8
4: orange day_8 0
5: hammer day_3 3
6: hammer day_4 0
7: hammer day_5 70
8: hammer day_6 70
9: hammer day_7 0
10: hammer Day_8 80
,因为这只会为您的第一个连续零和非零后的0提供0(如果您的数据中没有负值,我假设这里)。然后,结果自动组合。所以,让我们这样做:
require(data.table)
dt <- data.table(df)
dt[, .SD[cummax(qty_sold)>0], by = item]
总结一下:
by = item
有关语法的更多解释。我们先考虑split
。这是item
内部data.table
为您提供的数据的部分(即,item= orange
的整个item = hammer
将被视为第一个,后面是.SD[cummax(qty_sold) > 0]
的部分{1}}等等。)
中间部分apply
是神奇发生的地方 - .SD
等效函数。在这里,item
只是拆分部分(对应于.SD
一次采取一个部分。为了更清楚地了解每次dt[, print(.SD), by = item]
中的内容,请执行:{{1}}。
这基本上会删除在开始时具有连续0的行并保留其他所有内容(只要没有负值,解决方案就会得到保证)。
答案 1 :(得分:2)
SAS方法类似于:跟踪保留变量是否已经遇到项目的正值。如果没有,则不输出。如果是,请在用于跟踪它的变量中记下它。在项目的最后一行之后,重置您的跟踪变量。 例如:(必要时排序)
data RESULT (drop=found_first_positive);
set DATASET;
by item date;
retain found_first_positive 0;
if quantity>0 then found_first_positive=1;
if found_first_positive;
if last.item then found_first_positive=0;
run;