1
votes

I need to transpose a df in R and the aggregtion function has to be min.

Example:

library(reshape2)
N <- 20
df <- data.frame(rutcli=sample(101:103, N, replace=T), 
             mes_atras=sample(1:4, N, replace=T), pay_day=sample(1:30, N, replace=T))


s<-dcast(df, rutcli ~ mes_atras, fun.aggregate = min, value.var = 'pay_day')
View(s)

But I get a warning:

Warning message: In .fun(.value[0], ...) : no non-missing arguments to min; returning Inf

And the results are not the desired:

  rutcli   1    2   3   4
    101    1    1   Inf 1
    102    Inf  2   14  8
    103    3    6   2   25

How can I solve this?

Thanks

3
You should give the actual data frame (with dput) or set a random seed, to make your desired results reproducible. - Matthew Lundberg

3 Answers

2
votes

You're getting the warning because you're asking for the minimum value of an empty set. For example, there are no values of pay_day for which rutcli=102 and mes_atras=1, so Inf is returned instead.

You can see this more easily if you set fun.aggregate=length. For example:

library(reshape2)
N <- 20

set.seed(11) # To make the `sample` function reproducible
df <- data.frame(rutcli=sample(101:103, N, replace=T), 
                 mes_atras=sample(1:4, N, replace=T), 
                 pay_day=sample(1:30, N, replace=T))

dcast(df, rutcli ~ mes_atras, fun.aggregate = length, value.var = 'pay_day')

  rutcli 1 2 3 4
1    101 4 4 2 0
2    102 1 3 1 0
3    103 2 2 0 1

The zeros represent combinations of rutcli and mes_atras for which there are no values of pay_day. If we run dcast on this data frame with the min function, we'll get Inf where the zeros appear:

dcast(df, rutcli ~ mes_atras, fun.aggregate = min, value.var = 'pay_day')

  rutcli  1  2   3   4
1    101  1  5   7 Inf
2    102 18 13  14 Inf
3    103 10 13 Inf   7
Warning message:
In .fun(.value[0], ...) : no non-missing arguments to min; returning Inf

You can get NA instead of Infby using one of the split-apply-combine methods. @MatthewLundberg gives a base R method. Here's one with dplyr:

library(dplyr)

df %>% 
  group_by(rutcli, mes_atras) %>%
  summarise(min_pay_day=min(pay_day)) %>%
  dcast(rutcli ~ mes_atras, value.var="min_pay_day")

  rutcli  1  2  3  4
1    101  1  5  7 NA
2    102 18 13 14 NA
3    103 10 13 NA  7
1
votes

You can do this with aggregate and reshape from package stats:

reshape(
        aggregate(pay_day ~ mes_atras + rutcli, data=df, FUN=min),
        direction='wide', timevar='mes_atras', idvar='rutcli'
)
##   rutcli pay_day.1 pay_day.2 pay_day.3 pay_day.4
## 1    101         1        20        15         2
## 5    102        18        30        NA         3
## 8    103         2         5        23        16

You can replace NA values with Inf if desired.

Here's my df:

structure(list(rutcli = c(103L, 103L, 103L, 103L, 103L, 103L, 
102L, 102L, 103L, 102L, 101L, 101L, 101L, 101L, 101L, 103L, 102L, 
101L, 101L, 103L), mes_atras = c(1L, 3L, 4L, 1L, 1L, 2L, 1L, 
4L, 1L, 2L, 2L, 4L, 3L, 2L, 2L, 4L, 4L, 4L, 1L, 2L), pay_day = c(3L, 
23L, 16L, 18L, 2L, 5L, 18L, 3L, 12L, 30L, 20L, 2L, 15L, 24L, 
29L, 24L, 3L, 19L, 1L, 12L)), .Names = c("rutcli", "mes_atras", 
"pay_day"), row.names = c(NA, -20L), class = "data.frame")
0
votes

I did it with:

my.min <-  function (v) {if (length(v) == 0) 0 else min(v)} 
s<-dcast(df, rutcli ~ mes_atras, fun.aggregate = my.min, value.var = 'pay_day')

And because I know that I don't have any 0: s[s == 0] <- NA