Reputation: 313
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
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
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:
Use apply
only on specific columns:
df[,1:3] <- apply(df[,1:3], 2, sprintf, fmt="%02f")
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
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
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