anrisakaki96
anrisakaki96

Reputation: 313

How can I use a for-loop to use a paste0 function on multiple variables in a dataframe?

My df looks like this:

N = 1000

a <- rnorm(N)
b <- rnorm(N)
c <- rnorm(N)

df <- data.frame(a, b, c)

For each of these variables, I would like to perform the following function:

ifelse(df$`i` < 10, paste0("0", df$`i`), paste0(df$`i`))

where i is a , b and c.

Is there a way I can do this in a for-loop? Thanks :)

Upvotes: 0

Views: 175

Answers (4)

TarJae
TarJae

Reputation: 78927

I believe you need something like this: It is a step by step approach to your expected output: I also tried many other approaches like the ones provided and str_pad etc...: This is what remained:

library(tidyverse)

df %>% 
  mutate(id = row_number()) %>% 
  group_by(id) %>% 
  pivot_longer(-id) %>% 
  mutate(value_1 = abs(value),
         flag = ifelse(value < 0, 1, 0)) %>% 
  separate(value, c("x", "y"), sep="\\.", remove=FALSE) %>% 
  mutate(a_2 = str_remove(x, "\\-")) %>% 
  mutate(a_3 = ifelse(flag==1, paste0("-0", a_2,".",y), paste0("0", a_2,".",y))) %>% 
  select(id, name, a_3) %>% 
  pivot_wider(names_from = name,
              values_from = a_3)
  id a                    b                    c                  
   <int> <chr>                <chr>                <chr>              
 1     1 00.83703937073315    00.366414734799458   -00.506855403588713
 2     2 00.580328951041423   -00.0357083070697868 -01.62134408966926 
 3     3 00.495571975285419   00.162768262892583   01.68826302987719  
 4     4 00.437914572734454   02.77606270222216    01.80178764150532  
 5     5 -00.210379665334053  00.78351341898311    02.18889506889943  
 6     6 01.3275944819007     00.479437215663991   00.749247380828137 
 7     7 00.152210032721289   -01.75693137654597   -00.498625165370701
 8     8 -00.345283883367533  -01.0112672451135    -00.523111702183683
 9     9 -01.3690761805442    01.14671180216896    -01.95809501446637 
10    10 00.00701043853672493 00.849713993339966   00.50372111645798  
# ... with 990 more rows

Upvotes: 0

r2evans
r2evans

Reputation: 160447

If you're hoping to keep them in the frame, then the use of apply comes with a little risk: if there are any character columns existing in it, then when apply converts to a matrix before processing, you will have lost the number-ness of your other columns. (I don't know if your intended use is any more complicated than your sample data.)

Ways to mitigate this:

  1. Use apply only on specific columns:

    df[,1:3] <- apply(df[,1:3], 2, sprintf, fmt="%02f")
    
  2. Use lapply:

    df[1:3] <- lapply(df[1:3], sprintf, fmt="%02f")
    

    Or of you're operating on the whole frame,

    df[] <- lapply(df, sprintf, fmt="%02f")
    

    The df[] <- is necessary because lapply returns a list, losing the data.frame class. By doing df[] <- instead, you're reassigning the contents without changing the class, so it retains its data.frame class.

Upvotes: 1

Brenton M. Wiernik
Brenton M. Wiernik

Reputation: 1306

apply(df, 2, \(i) ifelse(i < 10, paste0("0", i), i))

Or for this case, more simply:

apply(df, 2, formatC, width = 2, flag = "0")

Upvotes: 1

Andrea M
Andrea M

Reputation: 2462

Do you have to use a loop? dplyr's across lets you iterate a function over many columns:

library(dplyr)

df |> mutate(across(everything(),
             ~ifelse(.x < 10,
                     paste0("0", .x),
                     .x)))

Upvotes: 1

Related Questions