根据一个月的观察进行子集

时间:2014-11-22 04:23:31

标签: r dataframe plyr subset

我正在尝试对一些数据进行分配,并且仍然停留在清洁的最后部分。

我需要做的是计算每个人(6月,7月和8月)的每个人(indivID)的观察数量,并返回每个人的百分比而不丢失数据,然后保持这些观察结果超过75%。

我能够创建一个嵌套的for循环,但今天花了大约6个小时来处理。我希望能够通过使用ddply或其他功能来利用并行计算机,但非常丢失。

这是数据(注意这是一个非常小的子集,仅包括1:5的个体):  https://www.dropbox.com/s/fmk8900622klsgt/data.csv?dl=0

这是for循环:

epa.d <- read.csv("/.../data.csv")

#Function for loops
days <- function (month){
     if (month == 06) return(as.numeric(30))
     if (month == 07) return(as.numeric(31))
     if (month == 08) return(as.numeric(31))

}    

#Subset data for 75% in June, July, and August
    for (i in unique(epa.d$indivID)){
         for (j in unique(epa.d$year)){
              for (k in unique(epa.d$month)){
                   monthsum <- sum(epa.d$indivID == i & epa.d$year == j & epa.d$month == k   )
                   monthperc = (monthsum/days(k))* 100
                   if (monthperc < 75){
                        epa.d <- epa.d[! (epa.d$indivID == i & epa.d$year == j), ]  

                   }
              }
         }
    }

2 个答案:

答案 0 :(得分:2)

如果我理解正确,您希望每天对每个组合进行日常观察,其中至少有75%的天数进行臭氧测量。这是一种应该非常快的方法:

library(dplyr)  

# For each indivID, calculate percent of days in each month with 
# ozone observations, and keep those with pctCoverage >= 0.75
epa.d_75 = epa.d %>% 
  group_by(indivID, year, month) %>%
  summarise(count=n()) %>% 
  mutate(pctCoverage = ifelse(month==6, count/30, count/31)) %>%
  filter(pctCoverage >= 0.75)

我们现在有一个数据框epa.d_75,每个indivID-month-year有一行,覆盖率至少为75%。接下来,我们将每日数据合并到此数据框中,从而为每个独特的indivID-month-year每日观察一行。

# Merge in daily data for each combination of indivID-month-year that meets
# the 75% coverage criterion
epa.d_75 = merge(epa.d_75, epa.d, by=c("indivID","month","year"),
                 all.x=TRUE)

更新:要回答提交中的问题:

  1. 你能解释一下%&gt;%正在做什么,如果可能的话,你可以分解逻辑思考这个问题的方法。

    %>%是一个&#34;链接&#34;运算符,允许您一个接一个地链接函数,而不必在运行下一个函数之前存储上一个函数的结果。请查看dplyr Vignette以了解有关如何使用它的更多信息。以下是逻辑在这种情况下的工作原理:

    group_by通过分组变量拆分数据集,然后分别在每个组上运行下一个函数。在这种情况下,summarise计算indivIDmonthyear的每个唯一组合的数据框中的行数,然后mutate添加包含indivIDmonth的{​​{1}}小数覆盖率的列。 year然后删除filterindivIDmonth的任意组合,覆盖率低于75%。您可以随时停止链条,看看它在做什么。例如,运行以下代码以查看过滤操作之前的year内容:

  2. epa.d_75
    1. 为什么这比运行循环要快得多?我不太详细地知道答案,但是 epa.d_75 = epa.d %>% group_by(indivID, year, month) %>% summarise(count=n()) %>% mutate(pctCoverage = ifelse(month==6, count/30, count/31)) dplyr代码中完成了大部分的魔术,这比原始C更快。希望其他人可以提供更精确和详细的答案。

答案 1 :(得分:2)

另一种选择是使用data.table(类似于@ eipi10的dplyr方法),这将非常快。

library(data.table)
epa.d_75 <-  setDT(epa.d)[, list(pctCoverage=ifelse(month==6, .N/30,
               .N/31)),by=list(indivID, year, month)][pctCoverage >=0.75]

epa.d_75New = merge(epa.d_75, epa.d, by=c("indivID","month","year"),
             all.x=TRUE)

数据

epa.d <- read.csv('data.csv', row.names=1)