R - 使用for循环修改数据框中的列(并使用因子级别)

时间:2014-06-11 03:53:21

标签: r date for-loop vector r-factor

我试图将日期因素转换为可以由for循环引用的字符向量。 for循环应该替换" Day"中的NA值。数据框的列(如下所示),其值与日期相对应。

     Date    Time Axis1 Day Sum.A1.Daily
1 6/12/10 5:00:00    20  NA           NA
2 6/12/10 5:01:00    40  NA           NA
3 6/13/10 5:02:00    50  NA           NA
4 6/13/10 5:03:00    10  NA           NA
5 6/14/10 5:04:00    20  NA           NA
6 6/14/10 5:05:00    30  NA           NA

我需要将其转换为:

     Date    Time Axis1 Day Sum.A1.Daily
1 6/12/10 5:00:00    20   1           60
2 6/12/10 5:01:00    40   1           60
3 6/13/10 5:02:00    50   2           80
4 6/13/10 5:03:00    30   2           80
5 6/14/10 5:04:00    20   3           50
6 6/14/10 5:05:00    30   3           50

使用我当前的代码,我得到的是:

     Date    Time Axis1 Day Sum.A1.Daily
1 6/12/10 5:00:00    20  NA           60
2 6/12/10 5:01:00    40  NA           60
3 6/13/10 5:02:00    50  NA           80
4 6/13/10 5:03:00    30  NA           80
5 6/14/10 5:04:00    20  NA           50
6 6/14/10 5:05:00    30  NA           50

我的for循环中的某些内容出错了,它将值分配给第4列。我需要帮助理解两件事:

  1. 问题是什么(下面的当前脚本)
  2. 如果我可以通过更有效地使用因子水平来规避问题
  3. 我是R和stackoverflow的新手 - 这个社区有多酷。如果我违反了一个基本的问题规则,请告诉我。

    ## read in file; define classes 
    ## (important b/c I want R to utilize factor levels of "Date" in column 1 of .csv file)
    dat <- read.csv("data.csv", header = T, ## read in file
          colClasses = c("factor", "character", "integer", "integer", "integer"))
    
    ## assign values to be used by for loops
    levs <- lapply(dat, levels) ## grab levels for factor variable of dates
    dates <- c(levs$Date) ## creates list of dates to reference in for loop
    counts <- c(1:length(dates)) ## creates vector 1:number of dates listed in file for loop 2
    x <- (1:nrow(dat)) ## creates vector 1:number of rows in file
    
    ## for loop 1 will cycle through rows in file; 
    ## for loop 2 cycle through values in "counts" variable
          ## if() compares value of each object in "Dates" (col. 1) 
           ## to one of the value of one of the levels (e.g., compared to "6/22/10", not 1)
                ## if ==, assigns corresp. value of "counts" to the appropriate obs. of col. 4 
    
    ("Day")
        for (i in x) {
              for (j in counts) {
                    if (dat[i,1] == levs[j]) {
                          dat[i,4] <- counts[j]
                    }
              }
        }
    dat <- transform(dat, Sum.A1.Daily = ave(dat$Axis1, dat$Date, FUN = sum))
    if(!file.exists("ActData.csv")) {     ## Enter file name for new data
    write.csv(dat, file = "ActData2.csv") ## Enter file name for new data
      } else { stop("change file name") 
    }
    print("File Cleaning Complete")
    head(dat)
    tail(dat)
    

2 个答案:

答案 0 :(得分:1)

这是循环非常低效的问题。尝试使用矢量化方法:

dat$day <- as.numeric(factor(dat$Date))  
dat$Sum.A1.Daily <- ave(dat$Axis1, dat$Date, FUN=sum)

第一个使用因子实际上是α水平向量的整数索引。在这种情况下,我们只是丢弃levels属性,只使用整数系列。

编辑:等等!你已经在transform中正确使用了它:ave计算第二个参数类别中FUN参数的值,并返回一个与第一个参数长度相同的向量。

答案 1 :(得分:0)

您可以使用match获取&#34; Day&#34;的值。柱。然后使用split sapply获取&#34; Sum.A1.Daily&#34;的值。柱。假设您的原始数据为dat

> within(dat, {
      Day <- match(Date, levels(Date))
      Sum.A1.Daily <- sapply(split(Axis1, Day), sum)[Day]
  })
#      Date    Time Axis1 Day Sum.A1.Daily
# 1 6/12/10 5:00:00    20   1           60
# 2 6/12/10 5:01:00    40   1           60
# 3 6/13/10 5:02:00    50   2           80
# 4 6/13/10 5:03:00    30   2           80
# 5 6/14/10 5:04:00    20   3           50
# 6 6/14/10 5:05:00    30   3           50

要打破这些部分,让我们分别看看它们。首先,在列上使用match以及列的因子级别将返回一个数字向量,其中包含列中属于每个级别的值的索引。

> (m <- with(dat, match(Date, levels(Date))))
# [1] 1 1 2 2 3 3

然后,拆分&#34; Axis1&#34; &#34;日期&#34;列并迭代以得到总和,用[m]矢量化,我们得到以下结果。

> with(dat, sapply(split(Axis1, Date), sum)[m])
# 6/12/10 6/12/10 6/13/10 6/13/10 6/14/10 6/14/10 
#      60      60      80      80      50      50 

within()允许我们对数据帧执行操作并在一次调用中返回结果。


现在,就您的代码而言,我会对您使用transform的位置进行以下更改

dates <- lapply(dat, levels)$Date 
  ## grab levels for factor variable of dates
counts <- match(dat$Date, levels(dat$Date)) 
  ## creates vector 1:number of dates listed in file for loop 2
for(i in seq(dates)){
    for(j in seq(counts)){
        if(dat$Date[j] %in% dates) dat$Day[j] <- counts[j]
    }
}