2016-11-20 83 views
1

我有一个数据框,其中包含有关许多卖家ID的信息以及他们卖出的期限。如果他们没有在接下来的6个阶段进行抛售,我想创建一个名为“非活跃”的新列。基于R中的多个列条件有效指定新的列值

这里是一个样本数据集的dput:

structure(list(SellerID = c(1, 7, 4, 3, 1, 7, 4, 2, 5, 1, 2, 
5, 7), Period = c(1, 1, 1, 2, 2, 3, 3, 5, 5, 9, 9, 10, 10)), .Names = c("SellerID", 
"Period"), row.names = c(NA, -13L), class = "data.frame") 

这里是我的理想结果的dput(第5行有1的无效,因为该行,sellerID 1在时期2中做了销售, 。但他接下来的销售是在周期9排10]因此,他是不活动的至少6个周期,因此,我们要记录,为了预测当卖方将处于非活动状态):

structure(list(SellerID = c(1, 7, 4, 3, 1, 7, 4, 2, 5, 1, 2, 
5, 7), Period = c(1, 1, 1, 2, 2, 3, 3, 5, 5, 9, 9, 10, 10), Inactive = c(0, 
0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0)), .Names = c("SellerID", 
"Period", "Inactive"), row.names = c(NA, -13L), class = "data.frame") 

我尝试使用nest-for循环方法解决这个问题,但是我的数据集非常大,并且需要很长的时间需要运行的时间(大约200,000行)。我也在示例数据集上尝试过我的方法,但似乎无效。这里是我下面的方法:

full.df$Inactive <- NA 
for (i in 1:nrow(full.df)){ 
    temp = subset(full.df, SellerID = unique(full.df$SellerID[i])) 
    for(j in 1:(nrow(temp) -1)){ 
    if(temp$Period[j+1] - temp$Period[j] <6) 
     temp$Inactive[j] <-0 
    else 
     temp$Inactive[j] <-1 
    } 
    full.df[rownames(full.df) %in% rownames(temp), ]$Inactive <- temp$Inactive 
} 

从虚拟数据集的输出,用我的方法把一个0在“无效”的所有行除最后一行NA。下面是我得到的输出dput:

structure(list(SellerID = c(1, 7, 4, 3, 1, 7, 4, 2, 5, 1, 2, 
5, 7), Period = c(1, 1, 1, 2, 2, 3, 3, 5, 5, 9, 9, 10, 10), Inactive = c(0, 
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NA)), .Names = c("SellerID", 
"Period", "Inactive"), row.names = c(NA, -13L), class = "data.frame") 
+1

使用'dput'来分享样本数据,并试图解决这个问题。 –

+0

我编辑了我的帖子来描述我解决这个问题的尝试。不幸的是,我不能共享样本数据,因为数据很敏感,我已经签署了保密合同。 –

+0

你可以创建一个虚拟样本数据并解释你的问题,因为我仍然失去了逻辑。 –

回答

1

我在这里假设1件事情。周期变量的最大范围为12.

这里是逻辑:您订购数据帧。然后你将12追加到列表的末尾,并有所作为。这也可以将卖家3分类为7天不活跃的卖家。

df_s=df[with(df, order(SellerID, Period)),] 
g=split(df$Period, df$SellerID) 
l=lapply(g, function(x) c(x,12)) 
j=lapply(l, diff) 
u=unlist(j, use.names = F) 
df_s$ind=ifelse(u>=7,1,0) 
+0

非常感谢Chirayu回答这个问题,并指导我发布到stackoverflow的一般操作。对此,我真的非常感激。 –

+0

我学到了同样的道理!最终它会为用户解决问题。 –

0

使用R --vanilla

# your input dataframe 
d <- structure(list(SellerID = c(1, 7, 4, 3, 1, 7, 4, 2, 5, 1, 2, 
5, 7), Period = c(1, 1, 1, 2, 2, 3, 3, 5, 5, 9, 9, 10, 10)), .Names = c("SellerID", 
"Period"), row.names = c(NA, -13L), class = "data.frame") 

# your wanted output 
o <- structure(list(SellerID = c(1, 7, 4, 3, 1, 7, 4, 2, 5, 1, 2, 
5, 7), Period = c(1, 1, 1, 2, 2, 3, 3, 5, 5, 9, 9, 10, 10), Inactive = c(0, 
0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0)), .Names = c("SellerID", 
"Period", "Inactive"), row.names = c(NA, -13L), class = "data.frame") 

# 6 steps solution, step by step using vanilla R 
# step1. - add tmp key for final sorting 
d$tmp.key <- seq_len(nrow(d)) 
# step 2. - split by individual seller id 
d.tmp <- split(d,f=d$SellerID) 
# step 3. - add inactive column to individual sellers 
d.tmp <- lapply(d.tmp, 
    function(x){ 
     # Below as.numeric is optional 
     # it may stay logical as well. 
     # Also sorting by Period (not used here) 
     # should be done (I am asuming it is sorted.) 
     x$Inactive <- as.numeric(c(diff(x$Period) >= 6,FALSE)) 
     x 
     }) 
# step 4. - assemble again individual sellers back into one data.frame 
d <- do.call(rbind,d.tmp) 
# step 5. - sort to original order using temp.key 
d <- d[order(d$tmp.key),c("SellerID","Period","Inactive")] 
# step 6. - rename rows according the row order 
rownames(d) <- NULL 

# here I am just comparing with your wanted ideal 
> identical(d,o)  
[1] TRUE 

对于data.frame 1条000 000线和1个卖家运行时将正常或多或少1秒PC。