3
votes

R beginner here: After searching for what must be a simple answer for over a day, decided to post my first ever question on here:

I would like to multiply (or divide) numeric columns in a dataframe with a numeric vector. The dataframe contains not just numbers but also strings. In my search I've learned about t(t(mydf) * myvec)), sweep(), scale(), *apply() and replacement operations, but I'm having trouble figuring out a clever function to allow me to specify which columns are multiplied without subsetting the dataframe.

How can multiply/divide each row in the last two columns of test.dat with myvec and get back a dataframe that contains the result along with the unaltered columns> (Yes for the numerics I could just add a '1' to myvec). But how do I deal with the names? Thank you in advance!!

Proper Example:

mydf <-as.data.frame(rbind(c("chrX", 5624624, 5631869, "Nudt11", 2, "+", 1, 7245, 1.332, 9651.3), c("chrX", 5977262, 6210835, "Shroom4", 9, "+", 1, 233573, 1.357, 316914)))

colnames(mydf)<-c("chr", "start", "end", "name", "score", "strand", "score2", "width", "value", "value2")

myvec<-c(10, 0.0001)

2
your mydf is a matrix. when you rbind, if there is not at least one data.frame as input, the output will be "bind" (bound) as a matrix. Use data.frame(.) to create your input instead.Arun
The answers are still be valid, check my edited answer.Jouni Helske

2 Answers

4
votes

As already said, you are not dealing with the data.frame in your example. Let's make your data as data.frame first:

# bind the numerical values as variables (columns) of data.frame
mydf <-as.data.frame(cbind(
 c(1, 10, 3.6, 4.5, 5.4, 99), 
 c(12, 18, 9, 8.1, 7.2, 84)))

# give names to columns: 
names(mydf)<-c("somename","othername")

#multiply the wanted rows with myvec:

mydf[4:6,]<-myvec*mydf[4:6,]
mydf
  somename othername
1  1.00000  12.00000
2 10.00000  18.00000
3  3.60000   9.00000
4 40.50000  72.90000
5 54.00000  72.00000
6 16.50033  14.00028

EDIT: Again, your example data is not a data.frame, but after tweaking it to proper data frame where the numeric values really are numbers and not factors, this still works:

mydf[,9:10]<-myvec*mydf[,9:10]
mydf
   chr   start     end    name score strand score2  width     value     value2
1 chrX 5624624 5631869  Nudt11     2      +      1   7245 1.332e+01 96513.0000
2 chrX 5977262 6210835 Shroom4     9      +      1 233573 1.357e-04    31.6914

So you can choose whatever columns you want by using square brackets, just make sure the length of myvec is equal to the number of columns so you won't get any suprising results due to recycling.

1
votes

The first step is to change your character matrix mydf (it's not a data frame) to a data frame with named columns:

mydf2 <- setNames(as.data.frame("mode<-"(t(mydf[ , -1]), "numeric")), mydf[ , 1])

> mydf2
  somename othername
1      1.0      12.0
2     10.0      18.0
3      3.6       9.0
4      4.5       8.1
5      5.4       7.2
6     99.0      84.0

Then it will be easy to apply the multiplication with myvec:

res <- lapply(mydf2[4:6, ], "*", myvec)

Replace the values with the new values:

mydf2[4:6, ] <- res

> mydf2
  somename othername
1  1.00000  12.00000
2 10.00000  18.00000
3  3.60000   9.00000
4 40.50000  72.90000
5 54.00000  72.00000
6 16.50033  14.00028

Update

Based on your edit, here's a way to do it:

last2 <- tail(seq_along(mydf), 2) # find the index of the last two columns

# transform columns from factor to numeric and multiplicate with vector
res <- lapply(lapply(mydf[last2], 
                     function(x) as.numeric(as.character(x))), "*", myvec)

mydf[last2] <- res # replace values

> mydf
   chr   start     end    name score strand score2  width     value     value2
1 chrX 5624624 5631869  Nudt11     2      +      1   7245 1.332e+01 96513.0000
2 chrX 5977262 6210835 Shroom4     9      +      1 233573 1.357e-04    31.6914