2016-11-20 72 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。