在 r 中使用 for-loop and/or 函数优化和改进代码
Optimise and improve code using for-loop and/or functions in r
我有一个416x8的df,我的目标是根据一个列条件做几个瀑布图。我设法做到了,但到目前为止是一个超长的代码(~800 行)。我想优化我使用函数和循环所做的事情,但我被卡住了!
我的 df 结构是这样的,我只复制了一个列表,其余 8 个具有相同的结构,只是列表名称不同:
List of 9
$ R1 : grouped_df [38 x 8] (S3: grouped_df/tbl_df/tbl/data.frame)
..$ chemical_name: Factor w/ 38 levels "1,3-Diphenylguanidine",..: 24 28 11 27 1 13 3 33 26 21 ...
..$ cas_number : chr [1:38] "2164-08-1" "112-18-5" "613-62-7" "7311-30-0" ...
..$ Type : chr [1:38] "Pesticide" "Industrial" "Industrial" "Industrial" ...
..$ sites : chr [1:38] "R1" "R1" "R1" "R1" ...
..$ conc_uM : num [1:38] 0.0000393 0.0000131 0.0003774 0.00001 0.0002736 ...
..$ ECOSAR_uM : num [1:38] 0.0891 0.0701 3.1158 0.0989 4.4114 ...
..$ TU_ecosar : num [1:38] 0.000441 0.000187 0.000121 0.000101 0.000062 ...
..$ percent : num [1:38] 0.3932 0.167 0.1081 0.0906 0.0554 ...
..- attr(*, "groups")= tibble [1 x 2] (S3: tbl_df/tbl/data.frame)
.. ..$ sites: chr "R1"
.. ..$ .rows: list<int> [1:1]
.. .. ..$ : int [1:38] 1 2 3 4 5 6 7 8 9 10 ...
.. .. ..@ ptype: int(0)
.. ..- attr(*, ".drop")= logi TRUE
旧代码示例:
#1 add sequence of number according to percentage under new column "id"
df1$id <- seq_along(dt1$percent)
df2$id ..... and so on until df9
#2 repeat a "name" per df under new column "group"
df1$group <- rep("RS1", nrow(df1))
df2$group <- rep("RS2", nrow(df2)) ..... and so on until df9
#3 I did a cumulative sum of the percentages
df1$end <- cumsum(df1$percent)
df2$end <- cumsum(df2$percent) ..... and so on until df9
#4 and I inserted an starting value
df1$start <- c(0, head(df1$end, -0.000001))
df2$start <- c(0, head(df2$end, -0.000001))..... and so on until df9
新篇章!
我设法改进了第一部分,我对这个功能很满意,还在最后包含了一个循环,用于将列表拆分为单独的 dfs。
#split my df according the one column criteria, which created a list of 9
df_split <- split(df, df$sites)
然后,我定义了一个函数,以便将特定列转换为每个列表中的因素:
#My function
col.asfactor = function(x) {
x = mutate(x, chemical_name = as.factor(chemical_name))
}
我应用了这个函数,结果很好
#apply as.factor function
df_split<- lapply(df_split, col.asfactor)
如何在这里继续!!!!
如您所见,我的旧代码又长又乏味(#1、#2、#3、#4)。基本上,我不知道如何集成到函数或循环中 -> seq_along、rep、cumsum 和最后一部分以优化我的代码。
我想使用以下循环完成将我的 df 拆分为 9 个独立的代码,该循环使用 dummy_df:
new_dfs<-c("new_df1","new_df2"..... until "new_df9)
# for in Loop
for (i in 1:length(df_split)) {
assign(new_dfs[i], df_split[[i]])
}
欢迎提出任何建议,抱歉这么长post。
所以你有 1 个 416x8 的 df,你想创建 9 个 Nx4 的 df?正如评论所说,如果我们能看到您想要的最终结果的原始 df 和示例,那将更容易提供帮助。
一个想法是使用 data.table 或 dplyr。您可以使用所需的 4 列计算一个新的 data.table,然后拆分它们。
大致...
library(data.table)
dt=setDT(df)
dt.new=dt[,.(.N,cumsum(percent),c(0, head(end, -0.000001),by=.(percent)]
#left out the "name" column for now
我认为有两件事可以帮助您:
- 双括号语法
within
函数
双括号语法允许您动态访问列表的元素。 within
函数允许您仅使用变量名称访问数据框中的变量。这是一个例子:
# Create sample data
df1 <- data.frame(percent = runif(10))
df2 <- data.frame(percent = runif(10))
df3 <- data.frame(percent = runif(10))
# Put data frames in list
lst <- list(df1, df2, df3)
# View original data frames
lst
# [[1]]
# percent
# 1 0.2138321
# 2 0.6917669
# 3 0.9728134
# 4 0.5561451
# 5 0.5280783
# 6 0.2165940
# 7 0.6805653
# 8 0.7460168
# 9 0.4642024
# 10 0.1374181
#
# [[2]]
# percent
# 1 0.81437961
# 2 0.83216126
# 3 0.35431008
# 4 0.97873284
# 5 0.98803502
# 6 0.63465900
# 7 0.94215238
# 8 0.01400746
# 9 0.02533159
# 10 0.48631865
#
# [[3]]
# percent
# 1 0.26785198
# 2 0.76407906
# 3 0.48805437
# 4 0.74689735
# 5 0.04256571
# 6 0.44064283
# 7 0.14606584
# 8 0.44194330
# 9 0.28411423
# 10 0.07362424
# Loop through list and perform operations on all data frames
for (i in seq_along(lst)) {
lst[[i]] <- within(lst[[i]], {
id <- seq_along(percent)
group <- rep(paste0("RS", i), nrow(df))
end <- cumsum(percent)
start <- c(0, head(end, -0.000001))
}
)
}
# View results
lst
[[1]]
percent start end group id
1 0.2138321 0.0000000 0.2138321 RS1 1
2 0.6917669 0.2138321 0.9055990 RS1 2
3 0.9728134 0.9055990 1.8784124 RS1 3
4 0.5561451 1.8784124 2.4345575 RS1 4
5 0.5280783 2.4345575 2.9626358 RS1 5
6 0.2165940 2.9626358 3.1792298 RS1 6
7 0.6805653 3.1792298 3.8597950 RS1 7
8 0.7460168 3.8597950 4.6058119 RS1 8
9 0.4642024 4.6058119 5.0700142 RS1 9
10 0.1374181 5.0700142 5.2074323 RS1 10
[[2]]
percent start end group id
1 0.81437961 0.0000000 0.8143796 RS2 1
2 0.83216126 0.8143796 1.6465409 RS2 2
3 0.35431008 1.6465409 2.0008510 RS2 3
4 0.97873284 2.0008510 2.9795838 RS2 4
5 0.98803502 2.9795838 3.9676188 RS2 5
6 0.63465900 3.9676188 4.6022778 RS2 6
7 0.94215238 4.6022778 5.5444302 RS2 7
8 0.01400746 5.5444302 5.5584377 RS2 8
9 0.02533159 5.5584377 5.5837692 RS2 9
10 0.48631865 5.5837692 6.0700879 RS2 10
[[3]]
percent start end group id
1 0.26785198 0.000000 0.267852 RS3 1
2 0.76407906 0.267852 1.031931 RS3 2
3 0.48805437 1.031931 1.519985 RS3 3
4 0.74689735 1.519985 2.266883 RS3 4
5 0.04256571 2.266883 2.309448 RS3 5
6 0.44064283 2.309448 2.750091 RS3 6
7 0.14606584 2.750091 2.896157 RS3 7
8 0.44194330 2.896157 3.338100 RS3 8
9 0.28411423 3.338100 3.622215 RS3 9
10 0.07362424 3.622215 3.695839 RS3 10
我有一个416x8的df,我的目标是根据一个列条件做几个瀑布图。我设法做到了,但到目前为止是一个超长的代码(~800 行)。我想优化我使用函数和循环所做的事情,但我被卡住了!
我的 df 结构是这样的,我只复制了一个列表,其余 8 个具有相同的结构,只是列表名称不同:
List of 9
$ R1 : grouped_df [38 x 8] (S3: grouped_df/tbl_df/tbl/data.frame)
..$ chemical_name: Factor w/ 38 levels "1,3-Diphenylguanidine",..: 24 28 11 27 1 13 3 33 26 21 ...
..$ cas_number : chr [1:38] "2164-08-1" "112-18-5" "613-62-7" "7311-30-0" ...
..$ Type : chr [1:38] "Pesticide" "Industrial" "Industrial" "Industrial" ...
..$ sites : chr [1:38] "R1" "R1" "R1" "R1" ...
..$ conc_uM : num [1:38] 0.0000393 0.0000131 0.0003774 0.00001 0.0002736 ...
..$ ECOSAR_uM : num [1:38] 0.0891 0.0701 3.1158 0.0989 4.4114 ...
..$ TU_ecosar : num [1:38] 0.000441 0.000187 0.000121 0.000101 0.000062 ...
..$ percent : num [1:38] 0.3932 0.167 0.1081 0.0906 0.0554 ...
..- attr(*, "groups")= tibble [1 x 2] (S3: tbl_df/tbl/data.frame)
.. ..$ sites: chr "R1"
.. ..$ .rows: list<int> [1:1]
.. .. ..$ : int [1:38] 1 2 3 4 5 6 7 8 9 10 ...
.. .. ..@ ptype: int(0)
.. ..- attr(*, ".drop")= logi TRUE
旧代码示例:
#1 add sequence of number according to percentage under new column "id"
df1$id <- seq_along(dt1$percent)
df2$id ..... and so on until df9
#2 repeat a "name" per df under new column "group"
df1$group <- rep("RS1", nrow(df1))
df2$group <- rep("RS2", nrow(df2)) ..... and so on until df9
#3 I did a cumulative sum of the percentages
df1$end <- cumsum(df1$percent)
df2$end <- cumsum(df2$percent) ..... and so on until df9
#4 and I inserted an starting value
df1$start <- c(0, head(df1$end, -0.000001))
df2$start <- c(0, head(df2$end, -0.000001))..... and so on until df9
新篇章!
我设法改进了第一部分,我对这个功能很满意,还在最后包含了一个循环,用于将列表拆分为单独的 dfs。
#split my df according the one column criteria, which created a list of 9
df_split <- split(df, df$sites)
然后,我定义了一个函数,以便将特定列转换为每个列表中的因素:
#My function
col.asfactor = function(x) {
x = mutate(x, chemical_name = as.factor(chemical_name))
}
我应用了这个函数,结果很好
#apply as.factor function
df_split<- lapply(df_split, col.asfactor)
如何在这里继续!!!!
如您所见,我的旧代码又长又乏味(#1、#2、#3、#4)。基本上,我不知道如何集成到函数或循环中 -> seq_along、rep、cumsum 和最后一部分以优化我的代码。
我想使用以下循环完成将我的 df 拆分为 9 个独立的代码,该循环使用 dummy_df:
new_dfs<-c("new_df1","new_df2"..... until "new_df9)
# for in Loop
for (i in 1:length(df_split)) {
assign(new_dfs[i], df_split[[i]])
}
欢迎提出任何建议,抱歉这么长post。
所以你有 1 个 416x8 的 df,你想创建 9 个 Nx4 的 df?正如评论所说,如果我们能看到您想要的最终结果的原始 df 和示例,那将更容易提供帮助。
一个想法是使用 data.table 或 dplyr。您可以使用所需的 4 列计算一个新的 data.table,然后拆分它们。
大致...
library(data.table)
dt=setDT(df)
dt.new=dt[,.(.N,cumsum(percent),c(0, head(end, -0.000001),by=.(percent)]
#left out the "name" column for now
我认为有两件事可以帮助您:
- 双括号语法
within
函数
双括号语法允许您动态访问列表的元素。 within
函数允许您仅使用变量名称访问数据框中的变量。这是一个例子:
# Create sample data
df1 <- data.frame(percent = runif(10))
df2 <- data.frame(percent = runif(10))
df3 <- data.frame(percent = runif(10))
# Put data frames in list
lst <- list(df1, df2, df3)
# View original data frames
lst
# [[1]]
# percent
# 1 0.2138321
# 2 0.6917669
# 3 0.9728134
# 4 0.5561451
# 5 0.5280783
# 6 0.2165940
# 7 0.6805653
# 8 0.7460168
# 9 0.4642024
# 10 0.1374181
#
# [[2]]
# percent
# 1 0.81437961
# 2 0.83216126
# 3 0.35431008
# 4 0.97873284
# 5 0.98803502
# 6 0.63465900
# 7 0.94215238
# 8 0.01400746
# 9 0.02533159
# 10 0.48631865
#
# [[3]]
# percent
# 1 0.26785198
# 2 0.76407906
# 3 0.48805437
# 4 0.74689735
# 5 0.04256571
# 6 0.44064283
# 7 0.14606584
# 8 0.44194330
# 9 0.28411423
# 10 0.07362424
# Loop through list and perform operations on all data frames
for (i in seq_along(lst)) {
lst[[i]] <- within(lst[[i]], {
id <- seq_along(percent)
group <- rep(paste0("RS", i), nrow(df))
end <- cumsum(percent)
start <- c(0, head(end, -0.000001))
}
)
}
# View results
lst
[[1]]
percent start end group id
1 0.2138321 0.0000000 0.2138321 RS1 1
2 0.6917669 0.2138321 0.9055990 RS1 2
3 0.9728134 0.9055990 1.8784124 RS1 3
4 0.5561451 1.8784124 2.4345575 RS1 4
5 0.5280783 2.4345575 2.9626358 RS1 5
6 0.2165940 2.9626358 3.1792298 RS1 6
7 0.6805653 3.1792298 3.8597950 RS1 7
8 0.7460168 3.8597950 4.6058119 RS1 8
9 0.4642024 4.6058119 5.0700142 RS1 9
10 0.1374181 5.0700142 5.2074323 RS1 10
[[2]]
percent start end group id
1 0.81437961 0.0000000 0.8143796 RS2 1
2 0.83216126 0.8143796 1.6465409 RS2 2
3 0.35431008 1.6465409 2.0008510 RS2 3
4 0.97873284 2.0008510 2.9795838 RS2 4
5 0.98803502 2.9795838 3.9676188 RS2 5
6 0.63465900 3.9676188 4.6022778 RS2 6
7 0.94215238 4.6022778 5.5444302 RS2 7
8 0.01400746 5.5444302 5.5584377 RS2 8
9 0.02533159 5.5584377 5.5837692 RS2 9
10 0.48631865 5.5837692 6.0700879 RS2 10
[[3]]
percent start end group id
1 0.26785198 0.000000 0.267852 RS3 1
2 0.76407906 0.267852 1.031931 RS3 2
3 0.48805437 1.031931 1.519985 RS3 3
4 0.74689735 1.519985 2.266883 RS3 4
5 0.04256571 2.266883 2.309448 RS3 5
6 0.44064283 2.309448 2.750091 RS3 6
7 0.14606584 2.750091 2.896157 RS3 7
8 0.44194330 2.896157 3.338100 RS3 8
9 0.28411423 3.338100 3.622215 RS3 9
10 0.07362424 3.622215 3.695839 RS3 10