迭代函数,用于从数据框中的特定列减去列并使值出现在新列中

时间:2018-08-13 19:19:14

标签: r loops iteration

大家好,感谢您的阅读。

我一直在尝试创建一个函数,该函数将迭代地减去两列的值并将该值粘贴到新列中。为了显示我的意思,这是一个带有初始数据集的示例:

Sample  g1   g2   g3    g4   g5 
s001    5    10   15    20   25
s002    6    11   16    21   26
s003    7    12   17    22   27
s004    8    13   18    23   28

假设我要选择g3。然后,我想从g3中减去所有其他列,但将值显示在每列旁边的新列中。本质上,最终结果将如下所示:

Sample  g1  g1dt  g2  g2dt  g3  g3dt  g4  g4dt  g5dt  g5dt 
s001    5   10    10   5    15   0    20  -5    25    -10
s002    6   10    11   5    16   0    21  -5    26    -10
s003    7   10    12   5    17   0    22  -5    27    -10
s004    8   10    13   5    18   0    23  -5    28    -10

我尝试过的代码如下:

for (i in 2:6) {
dt <- paste0(names(dataset)[i]) #where names(dataset) is the ith name 
#from dataset
dataset[[dt]] <- dataset$g3 - dataset[[,2:6]] #[[]] is 
#supposed to create a new column "dt" added as a suffix
}

但这会导致以下错误:

Error in .subset2(x, ..2, exact = exact) : 
recursive indexing failed at level 3

对我可以尝试的方法有任何想法吗?如果需要清除任何令人困惑的问题,请告诉我。谢谢!

5 个答案:

答案 0 :(得分:3)

我们可以使用Thanks, Bala.

mutate_at

结果:

library(dplyr)

myfun <- function(DF, col){
  col_quo <- enquo(col)
  DF %>%
    mutate_at(vars(-Sample), funs(dt = !!col_quo - .)) %>%
    select(Sample, sort(current_vars())) %>%
    rename_all(funs(sub("_", "", .)))
}

myfun(df, g3)

注释:

  1. Sample g1 g1dt g2 g2dt g3 g3dt g4 g4dt g5 g5dt 1 s001 5 10 10 5 15 0 20 -5 25 -10 2 s002 6 10 11 5 16 0 21 -5 26 -10 3 s003 7 10 12 5 17 0 22 -5 27 -10 4 s004 8 10 13 5 18 0 23 -5 28 -10 将作为参数提供的表达式转换为quosure。稍后在enquo步骤中使用!!对它进行评估。

  2. mutate_at将函数应用于mutate_at中指定的thes列。如果像我一样vars那样将输出设置为变量,则会以dt = g3 - .为后缀自动创建新列。

  3. 由于OP表示他希望每个输出列都紧靠原始列,因此我们可以_dt sort并使用current_vars()来设置正确的列顺序,同时保持{ {1}}第一列。

  4. 最后一个select步骤是可选的,但是如果我们不希望Sample成为后缀的一部分,则可以使用rename_all_从列名称中删除所有rename_all

数据:

sub

答案 1 :(得分:2)

这将做您想要的。请注意,根据您的示例,myfun将第一列视为特殊列。

# example data
df <- data.frame(
    Sample = paste0("s00", 1:4),
    g1 = 5:8,
    g2 = 10:13,
    g3 = 15:18,
    g4 = 20:23,
    g5 = 25:28,
    stringsAsFactors = FALSE
)

# function to do what you want
myfun <- function(x, df) {
    mat <- df[[x]] - as.matrix(df[ , names(df)[-1]]) #subtract all cols from x
    colnames(mat) <- paste0(names(df)[-1], "dt")     #give these new cols names
    df <- cbind(df, mat)                             #add new cols to dataframe
    df <- df[ , c(1, order(names(df)[-1])+1)]        #reorder cols
    return(df)
}

# test it
myfun("g3", df)

# result
  Sample g1 g1dt g2 g2dt g3 g3dt g4 g4dt g5 g5dt
1   s001  5   10 10    5 15    0 20   -5 25  -10
2   s002  6   10 11    5 16    0 21   -5 26  -10
3   s003  7   10 12    5 17    0 22   -5 27  -10
4   s004  8   10 13    5 18    0 23   -5 28  -10

答案 2 :(得分:1)

这里是一种可能的dplyr解决方案:

library(dplyr)

# reproduce your data frame
df <- data_frame(
  Sample = c("s001", "s002", "s003", "s004"),
  g1 = 5:8,
  g2 = 10:13,
  g3 = 15:18,
  g4 = 20:23,
  g5 = 25:28
)

# compute the differences and arrange the order of columns
df %>%
  mutate(
    g1dt = g3 - g1,
    g2dt  = g3 - g2,
    g3dt  = g3 - g3,
    g4dt  = g3 - g4,
    g5dt  = g3 - g5,
  ) %>%
  select(1, 2, 7, 3, 8, 4, 9, 5, 10, 6, 11)

# # A tibble: 4 x 11
#   Sample    g1  g1dt    g2  g2dt    g3  g3dt    g4  g4dt    g5  g5dt
#   <chr>  <int> <int> <int> <int> <int> <int> <int> <int> <int> <int>
# 1 s001       5    10    10     5    15     0    20    -5    25   -10
# 2 s002       6    10    11     5    16     0    21    -5    26   -10
# 3 s003       7    10    12     5    17     0    22    -5    27   -10
# 4 s004       8    10    13     5    18     0    23    -5    28   -10

答案 3 :(得分:0)

您可以简单地创建一个新的数据框并从特定列中删除值。

df_new <- - df[, 2:6] + df[, 4]  # calculate subtractions
colnames(df_new) <- paste0(colnames(df_new), "dt")
df <- cbind(df, df_new)

此解决方案避免了无效循环,并且具有可伸缩性(您可以根据需要添加任意列)。

如果列的顺序对您来说很重要,则只需按名称排序即可;该解决方案符合您的列命名:

df <- df[, order(colnames(df))]

答案 4 :(得分:0)

R为基础:

fun <- function(df,x) {
  df[paste0(names(df)[-1],"dt")] <- df[["g3"]] - df[-1]
  df
}
fun(df,"g3")
#   Sample g1 g2 g3 g4 g5 g1dt g2dt g3dt g4dt g5dt
# 1   s001  5 10 15 20 25   10    5    0   -5  -10
# 2   s002  6 11 16 21 26   10    5    0   -5  -10
# 3   s003  7 12 17 22 27   10    5    0   -5  -10
# 4   s004  8 13 18 23 28   10    5    0   -5  -10

数据

df <- read.table(text="Sample  g1   g2   g3    g4   g5 
s001    5    10   15    20   25
s002    6    11   16    21   26
s003    7    12   17    22   27
s004    8    13   18    23   28",strin=F,h=T)