2
votes

Sorry for the confusing title, this one's a bit hard to describe. Basically, I've got two data tables which look similar to this:

df1 <- data.frame(SNP=c("W", "X", "Y", "Z"),
                  Gene.ID=c("A", "B", "C", "B"), pval=NA)
df2 <- data.frame(W=c(1, 0, 1), X=c(1, 1, 0), Y=c(0, 0, 1), Z=c(1, 0, 1),
                  A=c(3.5, 2.5, 3.5), C=c(4.5, 2.5, 1.5), B=c(1.5, 2.5, 1.5))

So all the entries in df1 correspond to column names in df2. My goal is to fill df1$pval with the p-values from a t-test. For every row in df1, I want to do a t-test comparing the df2 column that matches the value of df1$SNP, and compares that against the df2 column that matches the value of df1$Gene.ID.

For example, for the first row in df1, I would want to compare df2$W vs. df2$A, and then return the resulting p-value inside of df1[1, 3]. For the second row, I would compare df2$X vs. df2$B and return the p-value in df1[2, 3]. In other words, something like this:

for (i in 1:nrow(df1)){
  test <- t.test(df2[,which(colnames(df2)==df1[i, 1]] ~ df2[,which(colnames(df2)==df1[i, 2]])
  df1[i, 3] <- test$p.value
}

But this does not work because you can only select multiple column names using the colnames function, not just a single column name. Suggestions for how to get around this would be greatly appreciated--or if you have a simpler method in mind, that would be great too.

2

2 Answers

1
votes

I don't understand why you think this wouldn't work - I think your code just has syntax errors in it. The following code seems to work fine (note the change to use sapply, which is slightly more conventional in R):

df1[, 3] <- sapply(seq_len(nrow(df1)), 
  function(i) {
    test <- t.test(
      df2[, which(colnames(df2) == df1[i, 1])],
      df2[, which(colnames(df2) == df1[i, 2])])
    test$p.value
  })
1
votes

The use of which(colnames(df2)...) may not be the best choice here, since all you want to do is to select the columns of df2 that have df1[i,1] or df1[i,2] as names.

In R, one way to select a column by its name is to use the double brackets: e.g. df2[["A"]] will retrieve the column A of df2, which seems to be what you want, and less cumbersome than df2[, which(colnames(df2) == "A")].

With that in mind, you could rewrite your code like this:

for (i in 1:nrow(df1)){
  test <- t.test(df2[[df1[i, 2]]] ~ df2[[df1[i, 1]]])
  df1[i, 3] <- test$p.value
} 

Notice that I switched df1[i, 1] and df1[i, 2] since the documentation of t.test states that the binary variable has to be on the right hand side.

a formula of the form lhs ~ rhs where lhs is a numeric variable giving the data values and rhs a factor with two levels giving the corresponding groups