user9949797
user9949797

Reputation:

How to apply the result of a function to factors of a data.frame (R)?

I have a function (la) that I would like to apply to some data

la<-function(x) {
  res<-mean(x)^2
  return(c(res,res^2))
}

a<-c(1,3,5,6)
b<-c(5,8,9,10)
df<-data.frame(a,b)
colnames(df)<-c('tata','toto')
all<-stack(df)
> aggregate(all$values, by=list(all$ind), FUN=la)
  Group.1       x.1       x.2
1    tata   14.0625  197.7539
2    toto   64.0000 4096.0000

and I get the values for a :

> aggregate(all$values, by=list(all$ind), FUN=la)[,2][,1]
[1] 14.0625 64.0000

My question: Is it possible to create a new column to the data.frame 'all', where the third column will be the first column multiplied by 14.0625 and 64.0000 (depending on the factor) ?

Many thanks

Upvotes: 0

Views: 51

Answers (3)

IceCreamToucan
IceCreamToucan

Reputation: 28675

Using your custom function and aggregate code you could do

la<-function(x) {
  res<-mean(x)^2
  return(c(res,res^2))
}

agg <- aggregate(all$values, by=list(all$ind), FUN=la)
mult <- setNames(agg[,2][,1], agg[[1]])

all$all <- all$values*mult[all$ind]
all
#   values  ind      all
# 1      1 tata  14.0625
# 2      3 tata  42.1875
# 3      5 tata  70.3125
# 4      6 tata  84.3750
# 5      5 toto 320.0000
# 6      8 toto 512.0000
# 7      9 toto 576.0000
# 8     10 toto 640.000

However, if this is all you're trying to accomplish you don't need the custom function and aggregate, and can use the code below instead.

library(dplyr)

all %>% 
  group_by(ind) %>% 
  mutate(all = values*mean(values)^2)

# # A tibble: 8 x 3
# # Groups:   ind [2]
#   values ind     all
#    <dbl> <fct> <dbl>
# 1      1 tata   14.1
# 2      3 tata   42.2
# 3      5 tata   70.3
# 4      6 tata   84.4
# 5      5 toto  320  
# 6      8 toto  512  
# 7      9 toto  576  
# 8     10 toto  640  

Or with data.table

library(data.table)
setDT(all)

all[, all := values*mean(values)^2, by = ind]

all
#    values  ind      all
# 1:      1 tata  14.0625
# 2:      3 tata  42.1875
# 3:      5 tata  70.3125
# 4:      6 tata  84.3750
# 5:      5 toto 320.0000
# 6:      8 toto 512.0000
# 7:      9 toto 576.0000
# 8:     10 toto 640.0000

Upvotes: 2

jay.sf
jay.sf

Reputation: 72673

You may use ave.

all$newcol1 <- with(all, ave(values, ind, FUN=function(x) x * la(x)))
all
#   values  ind   newcol
# 1      1 tata  14.0625
# 2      3 tata  42.1875
# 3      5 tata  70.3125
# 4      6 tata  84.3750
# 5      5 toto 320.0000
# 6      8 toto 512.0000
# 7      9 toto 576.0000
# 8     10 toto 640.0000

Upvotes: 2

Gaffi
Gaffi

Reputation: 4367

You already have an answer, but another (more cumbersome) solution:

la<-function(x) {
  res<-mean(x)^2
  return(c(res,res^2))
}

a<-c(1,3,5,6)
b<-c(5,8,9,10)
df<-data.frame(a,b)
colnames(df)<-c('tata','toto')
all<-stack(df)

all_2 <- merge(
   all,
   aggregate(all$values, by=list(all$ind), FUN=la),
   by.x = 'ind',
   by.y = 'Group.1')
all_2$newvalue <- all_2$values * all_2$x[,1]
all_2 <- all_2[,c(1,2,4)]

# > all_2
#    ind values newvalue
# 1 tata      1  14.0625
# 2 tata      3  42.1875
# 3 tata      5  70.3125
# 4 tata      6  84.3750
# 5 toto      5 320.0000
# 6 toto      8 512.0000
# 7 toto      9 576.0000
# 8 toto     10 640.0000

Upvotes: 1

Related Questions