14

I have a dataframe. I'd like to subtract the 2nd column from all other columns. I can do it in a loop, but I'd like to do it in one call. Here's my working loop code:

df <- data.frame(x = 100:101, y = 2:3,z=3:4,a = -1:0,b=4:5)

for( i in 3:length(df) ) {
    df[i] <- df[i] - df[2]
}
TPM
  • 834
  • 4
  • 9
  • 20

3 Answers3

12

If you need to subtract the columns 3:ncol(df) from the second column

df[3:ncol(df)] <- df[3:ncol(df)]-df[,2]
akrun
  • 874,273
  • 37
  • 540
  • 662
  • Perfect. Thank you. I tried that, but didn't have the comma before the 2 so got an error saying the dataframes didn't match. – TPM Mar 04 '15 at 15:38
  • 1
    @TPM The `df[2]` is still a dataframe and the dimensions won't be matching with the other dataset, while `df[,2]` is a vector and it will do the subtraction for each column of `df[3:ncol(df)]` by recycling – akrun Mar 04 '15 at 15:41
  • great solution. I want to mention that the same approach does not work in a datatable. For example if you use a for loop, and want to subtract one column from several other columns by doing so, the typical syntax `..` or `with=F` doesnt work – ghx12 May 11 '23 at 21:19
  • @ghx12 You may do `setDT(df)[, (3:ncol(df)) := lapply(.SD, \(x) x - colnmsecond), .SDcols = 3:ncol(df)]` – akrun May 12 '23 at 06:04
5

Another solution using dplyr::mutate_at() function

# install.packages("dplyr", dependencies = TRUE)
library(dplyr)

df <- data.frame(x = 100:101, y = 2:3, z = 3:4, a = -1:0, b = 4:5)
df %>%
  mutate_at(vars(-matches("y"), -matches("x")), list(dif = ~ . - y))
#>     x y z  a b z_dif a_dif b_dif
#> 1 100 2 3 -1 4     1    -3     2
#> 2 101 3 4  0 5     1    -3     2

Update: starting from dplyr 1.0+, it's recommended to use across

df %>%
  mutate(across(c(-matches("y"), -matches("x")), ~ . - y, .names = "{col}_dif"))

Created on 2019-11-05 by the reprex package (v0.3.0)

Tung
  • 26,371
  • 7
  • 91
  • 115
  • Related https://stackoverflow.com/questions/48898121/mutate-multiple-variable-to-create-multiple-new-variables/ – Tung Nov 05 '19 at 14:16
0

This would also work - returns the 9 columns that you subtracted the second one from.

 df = data.frame(matrix(rnorm(100,0,1),nrow = 10))
 df[,-2] - df[,2]
Michael Discenza
  • 3,240
  • 7
  • 30
  • 41
  • 2
    The OP wants to subtract only from `3:ncol(df)` , you may need `df[-c(1:2)]` Having said that, this is basically the approach used by the solution I posted – akrun Mar 04 '15 at 15:45
  • @akrun, good catch, you're right. You would need that to get the same result as the code provided above – Michael Discenza Mar 04 '15 at 15:51