对多个 data.frames 执行循环,以接收包含不同 data.frames 值的表

Do a loop for multiple data.frames to receive a table with values from differen data.frames

提问人:dan 提问时间:11/9/2023 最后编辑:Phildan 更新时间:11/10/2023 访问量:48

问:

我需要为多个 data.frame 循环整个代码。现在这是 CEPSird2,但我也需要它来用于 CEPSird1、CEPSird3、...和其他人(见下文以获取数据)

我想得到的是:我有一个 data.frame(即 CEPSird2),我对“ird2”列感兴趣(其他 data.frames 的列是相等的,并且具有从 2015 年到 2022 年的多年值,但我只需要 >2018)。在第一个循环中,我创建了一个新的 data.frame (ÄnderungAbsolut),其中包含两年之间的绝对差异(“19/20”、“20/21”、“21/22”)。然后,我将这 3 列中的每一列拆分为只有正值和负值,并接收 6 个向量(正 20、正 21、负 20,....),每年两个。之后,我想为这 6 个向量中的每一个计算不同的数字(平均值、sd、基尼和函数 (x)),并将它们汇总到一个表格中(结果)。3X9 表现在是 3 年(“19/20”、“20/21”、“21/22”)和我感兴趣的 8 个数字。现在我需要同样的表,只是不是用于 CEPSird2 中的 ird2,而是用于 CEPSird1 和 ird3 inn CEPSird3 等中的 ird1。如果行前面有年份,而不是像现在这样有 1、2、3 年,以及它们来自哪里(ird2、ord、ird3 等),那就太好了

我知道这很多,但也许有人可以帮助我。多谢。

Test <- data.frame(year= rep(c(2018,2019,2020,2021,2022),6),
          id_zewo= rep(c(1:6),each=5),
          ird2=runif(30, min = 10000, max = 30000))

Test.id_zewo <- as.numeric(Test[Test$year==2019, c("id_zewo")])

result <- c()
for (i in Test.id_zewo) {
  value <- Test %>%
    filter(id_zewo %in% i, year > 2018) %>%
    select(3)
  Wert1 <- value$ird2[2]-value$ird2[1]
  Wert2 <- value$ird2[3]-value$ird2[2]
  Wert3 <- value$ird2[4]-value$ird2[3]
  result <- rbind(result, c(i,Wert1,Wert2,Wert3))
}
ÄnderungAbsolut <- as_tibble(result)
colnames(ÄnderungAbsolut) <- c("id_zewo","19/20","20/21","21/22")


positive20 <- ÄnderungAbsolut[ÄnderungAbsolut$`19/20`>0, ]
positive20 <- positive20[order(positive20$`19/20`, decreasing = TRUE), c("id_zewo","19/20")]

positive21 <- ÄnderungAbsolut[ÄnderungAbsolut$`20/21`>0, ]
positive21 <- positive21[order(positive21$`20/21`, decreasing = TRUE), c("id_zewo","20/21")]

positive22 <- ÄnderungAbsolut[ÄnderungAbsolut$`21/22`>0, ]
positive22 <- positive22[order(positive22$`21/22`, decreasing = TRUE), c("id_zewo","21/22")]

negative20 <- ÄnderungAbsolut[ÄnderungAbsolut$`19/20`<0, ]
negative20 <- negative20[order(negative20$`19/20`), c("id_zewo","19/20")]

negative21 <- ÄnderungAbsolut[ÄnderungAbsolut$`20/21`<0, ]
negative21 <- negative21[order(negative21$`20/21`), c("id_zewo","20/21")]

negative22 <- ÄnderungAbsolut[ÄnderungAbsolut$`21/22`<0, ]
negative22 <- negative22[order(negative22$`21/22`), c("id_zewo","21/22")]

df_listpos <- list(positive20,positive21,positive22)
df_listneg <- list(negative20,negative21,negative22)
  extracted_pos <- lapply(df_listpos, purrr::pluck, 2)
  extracted_neg <- lapply(df_listneg, purrr::pluck, 2)
  
mean_pos <- lapply(extracted_pos, mean) |> unlist()
mean_neg <- lapply(extracted_neg, mean) |> unlist()
  sd_pos <- lapply(extracted_pos, sd) |> unlist()
  sd_neg <- lapply(extracted_neg, sd) |> unlist()
    gini_pos <- lapply(extracted_pos, Gini) |> unlist()
    gini_neg <- lapply(extracted_neg, Gini) |> unlist()
      cumsum_pos <- lapply(extracted_pos, function(x) sum(cumsum(x)/sum(x)<0.75)) |> unlist()
      cumsum_neg <- lapply(extracted_neg, function(x) sum(cumsum(x)/sum(x)<0.75)) |> unlist()
results <- data.frame(id = 1:length(extracted_pos), mean_pos, mean_neg, sd_pos, sd_neg, 
                      gini_pos,gini_neg, cumsum_pos,cumsum_neg)

这是我数据的尾巴。年份范围从 2015 年到 2022 年,id_zewo 只是行中值的相应数字。我过滤掉 ird2,因为 CEPSird2,CEPSird3,...还有其他我现在不需要的变量。如果它能简化代码,我已经可以使用我需要的 3 个变量(“year”、“id_zewo”、“ird2”)来保护 CEPSird2,这样我就可以跳过这一步。 例如,ÄnderungAbsolut data.frame 给了我 id_zewo 500 在 19/20、20/21 和 21/22 之间的差异。

tail(CEPSird2[c("year","id_zewo","ird2","ird3")])
     year id_zewo    ird2    ird3
3859 2022     500  129302  802312
3861 2022     502 4399508 4658553
3867 2022     514  871262       0
3869 2022     518   86635       0
3871 2022     521  128275       0
3872 2022     522       0       0
R 循环 lapply

评论

0赞 uke 11/9/2023
为包含数据的尾巴而欢呼。更好的做法是声明一个对象,该对象仅包含您与我们共享的尾部数据,并将示例计算基于该对象,以便我们可以复制粘贴您的代码,并且它正在运行!目前,这仍然是不可能的。令我感兴趣的是,你是如何创建和其他数据框的(你在之前的问题中提到,有一个完整的数据集,你分解了很多)。您能否包括例如 以及你对它所做的操纵?CEPSird2CEPSdput(head(CEPS))
1赞 dan 11/9/2023
我在问题中更改了我的代码,现在您可以运行它了。但也许你在“结果”中没有得到很好的值,b/c 数字是 runif。CEPS 有 $ird 1、$ird 2、$ird 4 等列,而 CEPSird2 只是我需要的 $ird 2 列,但对于每个变量,我需要清理一些行 b/c,它们有错误的值,但对于不同的变量(ird2、ird1 等),它们并不相同,所以我创建了一个新的 data.frame (CEPSird2)。当然,可以使用来自不同子数据(CEPSird2、CEPSird1、CEPSird4,...)的列创建一个新的 data.frame,以便它们都位于一个together@uke
1赞 dan 11/9/2023
希望这对你有所帮助:)和我
0赞 uke 11/9/2023
非常感谢,这确实很有帮助。我必须再问一个问题:为什么这些列包含错误的值,是否可以用 s 替换这些错误的值,或者这会误导吗?我更喜欢这种方法,因为它允许我们保留 ,因为每列将具有相同数量的观测值,只是有些遗漏更多,而另一些则更少。这是处理数据的明智方法吗?irdNANACEPS
0赞 dan 11/9/2023
我的错,它们没有错误的值,这是因为也许它们在 2019 年有 NA,而在 2020 年的第二年它们有值,这误导了我的分析结果。这就是为什么我删除了这些分发此数据的行,但正如我所说的 ird1,ird2 大多数是相同的行,但不是 100%。

答:

0赞 I_O 11/9/2023 #1

一种通用方法,用于将相同的操作应用于数据帧列表并合并结果。 并成为您的数据帧:d1d2

    library(dplyr)

    d1 <- data.frame(year = 2018, value = rnorm(3), dummy_a = 'junk')
    d2 <- data.frame(year = 2019, value = rnorm(3), dummy_b = 'other junk')
    
    list(d1, d2) %>%
      Map(f = \(d){## some data processing, e. g.: tidyverse stuff
        d %>%
          select(year, value) %>%
          mutate(value = value * pi)
      }) %>%
      do.call(rbind, .)

输出:

    ##   year      value
    ## 1 2018  3.2673407
    ## 2 2018 -1.0875516
    ## 3 2018  0.2297448
    ## 4 2019 -1.6449955
    ## 5 2019 -0.4552625
    ## 6 2019 -3.8103155

评论

0赞 dan 11/9/2023
你能解释一下你在.不同的代码代表什么,它们有什么作用?list(d1, d2) %>%
0赞 I_O 11/9/2023
Map(或 {purrr} 的增强版本将函数应用于列表的每个元素,并返回作项的列表。在上述情况下,列表项是并且仍然是数据帧,然后出于性能原因使用这些数据帧进行组合。在上述情况下,其中的有效负载是一组示例性的 {dplyr} 表达式mapdo.call(rbind, list_of_dataframes)Map(...)
0赞 uke 11/9/2023
这是什么符号?我见过它几次,但不知道它是什么意思。\(d)
0赞 dan 11/9/2023
是的,很高兴知道:) 但是在我的例子中它会是什么样子?因为我有两个块,所以我需要重复太多,它们需要是公平的。@uke
1赞 I_O 11/9/2023
@uke:是定义函数的简写:相当于\(x) ...function(x) ...
0赞 uke 11/10/2023 #2

我将您的计算重写为代码。由于它的功能,避免了很多循环。简而言之,这使我们能够计算单独的汇总统计数据,例如每个 或每个 .这使我们能够跳过繁琐的创建许多小型中间数据帧。dplyrforgroup_byyearid

这是整个代码。 所有计算都包含在零件中。请参阅下面的代码细分。 将这些计算应用于许多数据框需要其他所有条件。data_wrangling

library(dplyr)

# create example data frames
test1 <- data.frame(year = rep(c(2018:2022), 6),
                    id_zewo = rep(c(1:6),each = 5),
                    ird1 = runif(30, min = 10000, max = 30000))

test2 <- data.frame(year = rep(c(2018:2022), 6),
                    id_zewo = rep(c(1:6), each = 5),
                    ird2 = runif(30, min = 100, max = 1000))

test3 <- data.frame(year = rep(c(2018:2022),6),
                    id_zewo = rep(c(1:6), each = 5),
                    ird3 = runif(30, min = 1, max = 100))

# create a list containing these data frames
df_list <- list(test1, test2, test3)

# one way to save some hassle is to rename 
# all `ird1, 2, 3... ` columns to "value".

# get old colnames
new_colnames <- names(test1)
# inject colname "value" instead of "ird..."
new_colnames[3] <- "value"

# apply column renaming to all data frames
df_list <- lapply(df_list, setNames, new_colnames)

# data wrangling starts
# defining a function that does all the work
# to be called later inside `lapply()`

data_wrangling <- function(x){
  x |>
  group_by(id_zewo) |>
  filter(year > 2018) |>
  mutate(year_diff = value - dplyr::lag(value)) |>
  ungroup() |>
  mutate(positive_diff = year_diff > 0) |> # This is a helper, allowing us to use group by
  group_by(positive_diff, year) |>
  summarise(mean = mean(year_diff),
            sd = sd(year_diff),
            n_below_3rd_quartile = sum(cumsum(year_diff) / sum(year_diff) < 0.75))
  #gini = Gini(year_diff)) # I dont know what package Gini is from
}

# apply data wrangling steps to all data frames
results <- lapply(df_list, data_wrangling)

# show results
results

结果

每个输入的数据框包含一个结果表的列表。

# [[1]]
# # A tibble: 7 × 5
# # Groups:   positive_diff [3]
# positive_diff  year   mean    sd n_below_3rd_quartile
# <lgl>         <int>  <dbl> <dbl>                <int>
#   1 FALSE          2020 -9098. 5046.                    2
# 2 FALSE          2021 -5562. 3180.                    3
# 3 FALSE          2022 -6050. 4858.                    2
# 4 TRUE           2020  7869. 4573.                    2
# 5 TRUE           2021  1950. 1915.                    0
# 6 TRUE           2022  6578. 6156.                    1
# 7 NA             2019    NA    NA                    NA
# 
# [[2]]
# # A tibble: 7 × 5
# # Groups:   positive_diff [3]
# positive_diff  year   mean    sd n_below_3rd_quartile
# <lgl>         <int>  <dbl> <dbl>                <int>
#   1 FALSE          2020 -150.  157.                     1
# 2 FALSE          2021 -348.  297.                     2
# 3 FALSE          2022  -36.5  NA                      0
# 4 TRUE           2020  596.  194.                     2
# 5 TRUE           2021  246.   40.5                    1
# 6 TRUE           2022  234.  145.                     3
# 7 NA             2019   NA    NA                     NA
# 
# [[3]]
# # A tibble: 7 × 5
# # Groups:   positive_diff [3]
# positive_diff  year   mean    sd n_below_3rd_quartile
# <lgl>         <int>  <dbl> <dbl>                <int>
#   1 FALSE          2020  -9.30  5.64                    1
# 2 FALSE          2021 -18.5  15.2                     2
# 3 FALSE          2022 -50.4  15.1                     3
# 4 TRUE           2020  21.0  29.8                     0
# 5 TRUE           2021  13.5  12.6                     2
# 6 TRUE           2022  47.1   9.07                    1
# 7 NA             2019  NA    NA                      NA

数据整理部分

让我们看看在自定义数据整理函数中做了什么。让我们以数据为例。test1

test1 |>
  group_by(id_zewo) |>
  filter(year > 2018) |>
  mutate(year_diff = ird1 - dplyr::lag(ird1)) |>
  ungroup() |>
  mutate(positive_diff = year_diff > 0) |> # This is a helper, allowing us to use group by
  group_by(positive_diff, year) |>
  summarise(mean = mean(year_diff),
            sd = sd(year_diff),
            n_below_3rd_quartile = sum(cumsum(year_diff) / sum(year_diff) < 0.75))
#gini = Gini(year_diff)) # I dont know what package Gini is from

这是一个分步总结。

  1. group_by(id_zewo)正在按 ID 对数据进行分组。这样可以确保以后为每个 id 单独计算 (您尝试在代码开头使用循环实现的目标)。difffor

  2. 筛选数据以排除 2019 年以下的年份

  3. 创建一个包含与上一年的差异的列。因为我们分组的依据是 ,所以这个差异是为每个 单独计算的。diffirdidid_zewo

    以下是此步骤中表格的样子:


test1 |>
  group_by(id_zewo) |>
  filter(year > 2018) |>
  mutate(year_diff = ird1 - dplyr::lag(ird1))

# Output:
# A tibble: 24 × 4
# Groups:   id_zewo [6]
# year id_zewo   ird1 year_diff
# <int>   <int>  <dbl>     <dbl>
# 2019       1 23248.       NA 
# 2020       1 19966.    -3282.
# 2021       1 23271.     3304.
# 2022       1 21833.    -1437.
# 2019       2 28372.       NA 
# 2020       2 16062.   -12310.
# 2021       2 10383.    -5678.
# 2022       2 23761.    13378.
# 2019       3 19182.       NA 
# 2020       3 27070.     7887.

请注意,我们的分组是有效的,因为在每个组中,差异都以 2019 年开始,因为 2019 年之前没有年份。idNAyear

  1. 删除分组

    我们这样做是因为以下汇总统计数据应由 而不是由 计算。我们想要 2019 年、2020 年等。但首先我们需要创建一个帮助程序列。yearidmean

  2. 创建一个帮助程序列,指示差异是否为正值。year_diff

  3. 按此帮助程序列和 进行分组,以便我们在后续步骤中获取每个单独年份的汇总统计信息,并分别获取正差异和负差异的汇总统计信息。positive_diffyear

  4. 计算汇总统计数据。您可以调整代码以包含我没有找到的函数。Gini

数据整理输出test1

# # A tibble: 7 × 5
# # Groups:   positive_diff [3]
# positive_diff  year   mean    sd n_below_3rd_quartile
# <lgl>         <int>  <dbl> <dbl>                <int>
# 1 FALSE          2020 -9098. 5046.                    2
# 2 FALSE          2021 -5562. 3180.                    3
# 3 FALSE          2022 -6050. 4858.                    2
# 4 TRUE           2020  7869. 4573.                    2
# 5 TRUE           2021  1950. 1915.                    0
# 6 TRUE           2022  6578. 6156.                    1
# 7 NA             2019    NA    NA                    NA

如何阅读此输出:

  • 正差异的汇总统计信息位于列中TRUEpositive_diff
  • 负差异的统计信息在行中,其中 是 。positive_diffFALSE
  • 最后一行可以忽略。它之所以在这里,是因为认为它本身就是一个群体。NAgroup_by(positive_diff)NA