函数从r中的一个特定列中减去每列

时间:2015-03-22 15:54:19

标签: r

我想从r中名为df $ Means的列中减去每列。我想这样做作为一个函数,但我不知道如何迭代每个列 - 每次迭代依赖于从df $ Means中减去一列,然后有一堆下游代码使用输出。我已经简化了这里的代码,因为这是给我带来麻烦的一点。到目前为止,我有:

CopyNumberLoop <- function (i) {df$ZScore <- (df[3:5]-df$Means)/(df$sd)
  } 
apply(df[3:50], 2, CopyNumberLoop)

但我不确定如何确保一次在一列上完成操作。我不认为df [3:5]是正确的吗?

I have been asked to produce a reproducible example so all the code I want is here:

df1&lt; - read.delim(file.choose(),header = TRUE)

    #Take the control samples and average each row for three columns excluding the first two columns- add the per row means to the data frame
    df$Means <- rowMeans(df[,30:32]) 
    RowVar <- function(x) {rowSums((x - rowMeans(x))^2)/(dim(x)[2] - 1)}
    df$sd=sqrt(RowVar(df[,c(30:32)]))

    #Get a Z score by dividing the test sample count at each locus by the average for the control samples and divide everything by the st dev for controls at each locus.

{         df $ ZScore&lt; - (df [,35] -df $ Means)/(df $ sd)

    ######################################### QUARTILE FILTER ###########################################################
    alpha=1.5
    numberofControls = 3
    UL = median(df$ZScore, na.rm = TRUE) + alpha*IQR(df$ZScore, na.rm = TRUE)
    LL = median(df$ZScore, na.rm = TRUE) - alpha*IQR(df$ZScore, na.rm = TRUE)

    #Copy the Z score if the score is > or < a certain number, i.e. LL or UL.
    Zoutliers <- which(df$ZScore > UL | df$ZScore < LL)
    df$Zoutliers <- ifelse(df$ZScore > UL |df$ZScore <LL ,1,-1)
    tempout = ifelse(df$ZScore[Zoutliers] > UL,1,-1)

    ######################################### Three neighbour Isolation filter ##############################################################################
    finalSeb=c()
    for(i in 2:(length(Zoutliers)-1)){
     j=Zoutliers[i]
     if(sum(ifelse((j-1) == Zoutliers,1,0)) > 0 & tempout[i] ==  tempout[i-1] & sum(ifelse((j+1) == Zoutliers,1,0)) > 0 & tempout[i] ==  tempout[i+1]){
       finalSeb = c(finalSeb,i)
     }  
    }
    finalset_row_number = Zoutliers[finalSeb]
    #View(finalset_row_number)
    p_seq = rep(0,nrow(df))
    for(i in 1:length(finalset_row_number)){
     p_seq[(finalset_row_number[i]-1):(finalset_row_number[i]+1)] = median(df$ZScore[(finalset_row_number[i]-1):(finalset_row_number[i]+1)])
    }

    nrow(as.data.frame(finalset_row_number))
    }

对于3到50之间的每一列,我想生成一个nrow(as.data.frame(finalset_row_number))并将其保存在另一个数据帧中。不可否认,我的代码很乱,因为我不知道如何创建允许我将其应用于每列的函数

2 个答案:

答案 0 :(得分:1)

您的代码根本没有使用参数i。实际上,i是当前列,因此您应该使用它:

result = apply(df[, 3 : 50], 2, function (col) col - df$Means)

或者你可以直接减去手段:

result = df[, 3 : 50] - df$Means

这将返回一个新的矩阵,该矩阵由df的第3-50列组成,依次从每个列中减去df$Means。或者,如果你想像你的代码那样计算Z分数:

result = (df[, 3 : 50] - df$Means) / df$sd

答案 1 :(得分:0)

似乎您希望将原始数据框中指定的Z分数作为命名列。如果您想循环使用列,那么使用lapplysapply同样经济。接收函数将依次接受每个列并将其与第一个参数匹配。接收函数之后提供的任何其他参数将通过名称或位置与参数列表中的任何其他符号/名称匹配。您没有对“df”进行任何分配。在函数内部:

CopyNumberLoop <- function (col) { col-df$Means/(df$sd)
                         } 
df[, paste0('ZScore' , 3:50)] <-  # assignment done outside the loop
         lapply(df[3:50], CopyNumberLoop)  # result is a list
                # but the `[.data.frame<-` method will accept a list.

将符号应用于矩阵,该矩阵可能会在列中产生不良影响,而不是数字(例如因子或日期时间)。在处理数据帧中的列范围时,最好养成使用lapply的习惯。

如果要将此操作的结果分配给新的数据帧,则需要将lapply(.)结果包装在as.data.frame中,然后才能分配列名。需要对apply(.)的结果进行同样的努力。