user4999605
user4999605

Reputation: 441

Use mutate_each to divide a set of rows in R by 2

I have a data frame like this

Letter   Number1 Number2 Number3 Type
A           4      5        3      10
B           10     22       24     20
C           50     24       100    30
D           60     32       12     40

Where I would like to use mutate_each to divide number1, number2, and number3 by 2, and not do anything to Letter and type. Is there an easy day to do this?

This is what I would want the final DF to look like

Letter   Number1 Number2 Number3 Type
A           2      2.5     1.5     10
B           5      11       12     20
C           25     12       50    30
D           30     16       6     40

Thanks!

Upvotes: 2

Views: 3393

Answers (3)

akrun
akrun

Reputation: 887163

We can select the 'Number' columns using starts_with or matches and divide those columns by 2.

library(dplyr)
mutate_each(df1, funs(./2), starts_with('Number'))
#    Letter Number1 Number2 Number3 Type
#1      A       2     2.5     1.5   10
#2      B       5    11.0    12.0   20
#3      C      25    12.0    50.0   30
#4      D      30    16.0     6.0   40

As @Cotton.Rockwood suggested in the comments, in the newer versions of dplyr (0.7.6), we can use mutate_at (for changing a subset of columns) or mutate_all (to change all the columns)

df1 %>%
   mutate_at(vars(starts_with("Number")), funs(./2))

Or using data.table, we convert the 'data.frame' to 'data.table' (setDT(df1)), get the column names that start with 'Number' ('nm1'), assign the 'nm1' with the new value ie. after dividing by '2'.

library(data.table)#v1.9.4+
setDT(df1)
nm1 <- grep('^Number', names(df1), value=TRUE)
df1[, (nm1):= lapply(.SD, `/`, 2), .SDcols=nm1]

Or a more efficient method with data.table for multiple columns would be using set.

for(j in nm1){
  set(df1, i=NULL, j=j, value=df1[[j]]/2)
}

data

 df1 <-  structure(list(Letter = c("A", "B", "C", "D"), Number1 = c(4L, 
 10L, 50L, 60L), Number2 = c(5L, 22L, 24L, 32L), Number3 = c(3L, 
 24L, 100L, 12L), Type = c(10L, 20L, 30L, 40L)), .Names = c("Letter", 
 "Number1", "Number2", "Number3", "Type"), class = "data.frame",
 row.names = c(NA, -4L))

Upvotes: 6

Cindy
Cindy

Reputation: 11

library(dplyr)

Create the test dataframe

letter <- c("A", "B", "C", "D")
n1 <- c(4, 10, 50, 60)
n2 <- c(5, 22, 24, 32)
n3 <- c(3, 24, 100, 12)
type <- c(10, 20, 30, 40)

df <- data.frame(letter, n1, n2, n3, type)

The dataframe df:

# letter n1 n2  n3 type
# 1      A  4  5   3   10
# 2      B 10 22  24   20
# 3      C 50 24 100   30
# 4      D 60 32  12   40

Make your own function

mydivide <- function(x){x/2}

Use funs() to tell mutate what function to use.

Use the '-' to tell mutate not to mutate columns 'letter' and 'type'

df <- mutate_each(df, funs(mydivide), -letter, -type)

The end result:

# letter n1   n2   n3 type
# 1      A  2  2.5  1.5   10
# 2      B  5 11.0 12.0   20
# 3      C 25 12.0 50.0   30
# 4      D 30 16.0  6.0   40

Upvotes: 1

Colonel Beauvel
Colonel Beauvel

Reputation: 31171

A base R solution in case:

indx <- grepl("Number", names(df))
df[indx] <- df[indx]/2L

 #>df
 #    Letter Number1 Number2 Number3 Type
 #1      A       2     2.5     1.5   10
 #2      B       5    11.0    12.0   20
 #3      C      25    12.0    50.0   30
 #4      D      30    16.0     6.0   40

Upvotes: 4

Related Questions