2015-12-30 136 views
2

我有一個數據框,如下所示。將值分配給R中的特定列和行

Name Amount Subscriptionperiod(Months) Subscriptionstart (Month) 
Tom 300 3        0 
Tom 100 3        2 
Jim 500 5        0 
Jim 600 3        1 

我想安排下面的數據。例如,湯姆在一筆交易中支付了300美元3個月。而在2個月後的第二筆交易中,他又支付了100美元3個月。

與Jim類似。

Name M0 M1 M2 M3 M4 M5 M6 
Tom 300 300 300 0 0 0 0 
Tom 0 0 100 100 100 0 0 
Jim 500 500 500 500 500 0 0 
Jim 0 600 600 600 0 0 0 

我無法改造。我使用下面的代碼來完成第一部分。但是如何在Jim的情況下創建第二行,其中值從M2開始。 100美元從M2開始並繼續到M4。

for(i in 0:6) df <- within(df,assign(paste0("M",i),ifelse((Subscriptionperiod>i),amount,0))) 

上面的代碼給出了不是我想要的以下輸出。幫助將不勝感激。

 Name M0 M1 M2 M3 M4 M5 M6 
    Tom 300 300 300 0 0 0 0 
    Tom 100 100 100 0 0 0 0 
    Jim 500 500 500 500 500 0 0 
    Jim 600 600 600 0 0 0 0 

回答

0

我使用data.table和plyr包來實現這一點。

library(data.table) 
library(plyr) 

df <- data.table(read.table(text='Name Amount Period Start 
            Tom 300 3  0 
            Tom 100 3  2 
            Jim 500 5  0 
            Jim 600 3  1', header=T, row.names = NULL)) 
#Create a row by repeating df$Amount, df$Period times and padding with 0 
create_rows <- function(x, y){ 
    c(rep(0, x$Start), rep(x$Amount, x$Period), rep(0, y - x$Period - x$Start)) 
} 

#Create a new data.table and add Name column 
df2 <- data.table(Name = df$Name) 

#Create an array of month names 
months <- paste('M', 0:6, sep = '') 

#Use adply (from plyr) to apply create_rows() accross all rows of df2 
#.expand = FALSE ensures the size of the returned data.frame is the right size 
#.id = NULL stops adply() from creating an index column 
#with = FALSE allows the variable month to be used to refer to columns 
df2[, months := adply(df, 
         1, create_rows, 
         length(months), 
         .expand = FALSE, 
         .id =NULL), 
    with = FALSE] 
+1

而不是'paste(...,sep ='')',你也可以使用'paste0(...)' –

+0

這樣可以跨越一個數據幀嗎?因爲我的來源是一個框架。 –

+0

您需要先使用setDT(df)將數據轉換爲data.table。 Data.table被設計爲data.frame的擴展。除少數例外情況外,數據框架操作仍然有效,如果需要,通過setDF()轉換回來很簡單。 – NGaffney

2
text1="Name Amount Subscriptionperiod(Months) Subscriptionstart(Month) 
Tom 300 3        0 
Tom 100 3        2 
Jim 500 5        0 
Jim 600 3        1" 

df1 <- read.table(text=text1, head=T, as.is=T) 

df2.lst <- apply(df1, 1, function(x){ 
    times <- x[3] 
    lst <- lapply(1:times, function(i){return(x[1:2])}) 
    df.lst <- as.data.frame(do.call(rbind, lst)) 
    df.lst$mon <- paste0("M", seq(from=as.numeric(x[4]), 
          length.out = as.numeric(x[3]))) 
    return(df.lst) 
}) 

df2 <- do.call(rbind, df2.lst) 

library(reshape2) 
df2$mon <- factor(df2$mon, levels = paste0("M", 0:6)) 
df3 <- dcast(df2, Name+Amount~mon, value.var = "Amount") 
df3$Amount <- NULL 
df3 
# Name M0 M1 M2 M3 M4 
# 1 Tom 300 300 300 <NA> <NA> 
# 2 Tom <NA> <NA> 100 100 100 
# 3 Jim 500 500 500 500 500 
# 4 Jim <NA> 600 600 600 <NA> 
+0

您可以使用'df3 [is.na(df3)] < - 0'將所有NA更改爲0 – ytk

+0

是的。你是對的。 @TejaK –

2

首先,讓我們從你的最小數據幀:

df1 <- data.frame(name=c("Tom", "Tom", "Jim", "Jim"), amount=c(300, 100, 500, 600), 
        Subperiod=c(3, 3, 5, 3), SubStart = c(0, 2, 0, 1)) 

> df1 
    name amount Subperiod SubStart 
1 Tom 300   3  0 
2 Tom 100   3  2 
3 Jim 500   5  0 
4 Jim 600   3  1 

接下來,實例化一個空的矩陣,其中ncol等於幾個月的#你想顯示:

m <- matrix(0, nrow=4, ncol=7) 

現在聰明的部分 - 做一個函數,將創建一個大的向量來填充基於矩陣的關閉你的規則

special_spread <- function(df1){ 
    bigrow <- c() 
    for(i in 1:nrow(df1)){ 
     pt1 <- rep(0, df1$SubStart[i]) 
     pt2 <- rep(df1$amount[i], df1$Subperiod[i]) 
     pt3 <- rep(0, ncol(m) - (length(pt2)+length(pt1))) 
     bigrow <- c(bigrow, pt1, pt2, pt3) 
    } 
    m1 <- as.data.frame(matrix(bigrow, nrow=4, ncol=7, byrow = TRUE)) 
    m1 <- cbind(df1$name, m1) 
    colnames(m1) <- c("name", paste0("M", 0:6)) 
    return(m1) 
} 

> special_spread(df1) 
    name M0 M1 M2 M3 M4 M5 M6 
1 Tom 300 300 300 0 0 0 0 
2 Tom 0 0 100 100 100 0 0 
3 Jim 500 500 500 500 500 0 0 
4 Jim 0 600 600 600 0 0 0 

請讓我知道如果這需要更多的解釋,如果這或多或少回答你的問題。

+0

得到一個錯誤矩陣中的錯誤(特殊(df1),nrow = 4,ncol = 7,byrow = TRUE): 找不到函數「special」 –

+0

@Vaibhav現在試一下,我換了'special(df1) '用'bigrow'。在我的部分錯別字。 –

相關問題