如何将具有许多计算的整个脚本应用于data.frame中的每一列

时间:2019-04-26 10:28:18

标签: r loops

我需要将多个计算应用于数据框中的一列。 为此,我提取了该列,创建了一个新的数据框,然后开始使用主要包含简单计算的新列来进行构建。 然后我需要对数据框中的每一列重复(相当长的脚本)。

应用族不起作用,因为我无法将所有计算都放到一个函数中(x)

我的原始数据帧如下所示,其中S是站点编号,值是生物量(1981:2007年和S1:S25年)。 我希望将下面的脚本应用于每个单独的列(每个站点),并为每个列使用单独的输出数据帧。

我的data.frame称为ts.bio,其中包含NA's

    year S1 S2 S3  S4  S5  S6  S7 S8  S9 S10 S11 S12 S13 S14 S15
    1981 94 91 92 103 162 104 125 91 108 101 117 138 115  95  99
    1982 33 52 52  73 109  40  41 55  51  77  77 100  54  44  62
    1983 26 14 30  29  46  14  16 25  11  24  31  31  19  11  28

这是我需要应用于每一列的脚本

    change<-NULL

    for (i in 1881:2007){
      lambda<-tsBio$S1[tsBio$year==i+1]/tsBio$S1[tsBio$year==i]
      change<-c(change, lambda)
         }


    print(change)

    #edit the data frame 
    change<-as.data.frame(change)  
    change$t<-c(1:26)    #add time 
    change$year<-c(1982:2007)   #add year 

    # I need DataCombine for the Insert Row line 
    library("DataCombine")
    NewRow<-c(0, 0, 1981)   #create new row
    change<-InsertRow(change, NewRow, RowNum=1) #ad new row

    change$biomass<- tsBio$S1   #add population size


    #create a lagged version to compute delta for differentiated B      (B')
    change$changelag<-change$change #duplicate column
    change$biomasslag<-change$biomass #duplicate column 
    change$tlag<-change$t


    #before this I need to detach dataCombine and activate data.table
    detach("package:DataCombine", unload=TRUE)
    library("data.table")
    change$changelag<-shift(change$changelag, n=1, type="lag")
    change$biomasslag<-shift(change$biomasslag, n=1, type="lag")
    change$tlag<-shift(change$tlag, n=1, type="lag")


    #compute nominator and denominator of differentiated B (B')
    change$deltaB<-(change$change-change$changelag)
    change$deltaX<- (change$biomass - change$biomasslag)

    change$Bdiff<-(change$deltaB/change$deltaX) 

    #compute mortality differentiated
    change$deltat<-(change$t-change$tlag)
    change$M<- change$change-(change$deltaX/change$deltat)

    change$Mdiff<-(change$M/change$biomass)

    change$lambda<-(change$Bdiff-change$Mdiff)

    library("ggplot2")
     ggplot(data=change, aes(x=year))+
     geom_point(aes(y=lambda))

我试图使用循环并应用家庭,但无能为力。创建一个函数(function(x))“套用”似乎很疯狂,因为脚本中有太多内容。

感谢sm的建议!对不起,很抱歉。

1 个答案:

答案 0 :(得分:0)

我建议将您的数据从宽格式转换为长格式,然后使用dplyr。在这种情况下,每一行都将用于观察,并会在列中列出年份,站点编号,λ,生物量等,并将所有数据保存在一个方便的数据框中。使用filter可以轻松提取某些站点,年份等数据。这是一个示例:

# Create dummy data frame
df <- data.frame(year = 1981:2007,
                 t = 1:27,
                 S1 = sample(1:200, 27, replace = TRUE),
                 S2 = sample(1:200, 27, replace = TRUE),
                 S3 = sample(1:200, 27, replace = TRUE),
                 S4 = sample(1:200, 27, replace = TRUE),
                 S5 = sample(1:200, 27, replace = TRUE))

# Quick peak
head(df)
#>   year t  S1  S2  S3  S4  S5
#> 1 1981 1 163 133  86  59  40
#> 2 1982 2  99  28 190 179  58
#> 3 1983 3  94 136   6  47 185
#> 4 1984 4 199  87 137  31  20
#> 5 1985 5 157 169 172  24  21
#> 6 1986 6 105  33 189 122 148

这是原始格式的原始数据的结构。让我们将其更改为长格式并进行一些计算。

# Load libraries
library(dplyr)
library(magrittr)
library(tidyr)


# 1) Convert to long format
# 2) Group by site for calculations
# 3) Calculate lambda, change in biomass
# 4) Ungroup
df %<>% 
  gather(site, biomass, S1:S5) %>% 
  group_by(site) %>% 
  mutate(lambda = biomass/lag(biomass),
         delta_biomass = biomass - lag(biomass)) %>% 
  ungroup

# Quick peak
head(df)
# # A tibble: 6 x 6
#    year     t site  biomass  lambda delta_biomass
#   <int> <int> <chr>   <int>   <dbl>         <int>
# 1  1981     1 S1        175 NA                 NA
# 2  1982     2 S1         74  0.423           -101
# 3  1983     3 S1        177  2.39             103
# 4  1984     4 S1         15  0.0847          -162
# 5  1985     5 S1         28  1.87              13
# 6  1986     6 S1        150  5.36             122

现在您的数据采用长格式,我们使用mutate进行了一些计算,这只是向您的数据框中添加了一些列。 (它也可以覆盖列。)请注意,我不必在计算中创建任何中间的滞后列,我只使用了lag。这样,您可以添加所有计算,而无需任何循环,这使得代码清晰易读。另外,像这样重组数据意味着您不必为每个站点列都这样做,因为它同时应用于所有站点。

起初,将所有这些数据集中在一起似乎很麻烦,但是使用filter从数据中提取所需的数据实际上非常容易。例如:

# Only see data for site S4 between 2000 and 2005
df %>% 
  filter(site == "S4", 
         between(year, 2000, 2005))
# # A tibble: 6 x 6
#     year     t site  biomass lambda delta_biomass
#    <int> <int> <chr>   <int>  <dbl>         <int>
# 1  2000    20 S4        124  1.38             34
# 2  2001    21 S4        116  0.935            -8
# 3  2002    22 S4        178  1.53             62
# 4  2003    23 S4         92  0.517           -86
# 5  2004    24 S4        107  1.16             15
# 6  2005    25 S4         87  0.813           -20

编辑

我错过了原始版本中的网站分组,现已更正。