1
votes

Appliquer une formule aux données dans R

Étant donné une formule comme log (y) ~ x ^ 2 + x * z + z comment puis-je appliquer la formule pour créer un nouveau data.frame à partir d'une donnée existante?

Pour exemple, laissez les données brutes (set.seed n'est vraiment pas nécessaire ici):

   df2 = data.frame(df,'log(y)'=log(df$y),'x^2'=df$x^2,'x*z'=df$x*df$z,z=df$z,check.names = FALSE)
> df2
            y         x            z     log(y)       x^2          x*z            z
1  0.80805320 2.0371328 7.645385e-01 -0.2131274 4.1499100 1.557466e+00 7.645385e-01
2  0.45052293 0.9700742 5.456879e-05 -0.7973463 0.9410439 5.293578e-05 5.456879e-05
3  1.36125062 0.5002969 5.911681e-03  0.3084039 0.2502970 2.957596e-03 5.911681e-03
4  1.43985610 0.7149159 2.062861e+00  0.3645432 0.5111048 1.474772e+00 2.062861e+00
5  0.31509256 0.4588976 9.477389e-01 -1.1548888 0.2105870 4.349151e-01 9.477389e-01
6  0.27022582 1.1975979 4.723059e-01 -1.3084973 1.4342407 5.656326e-01 4.723059e-01
7  0.62058948 0.9114911 2.877264e-01 -0.4770855 0.8308160 2.622601e-01 2.877264e-01
8  0.07162775 0.4323277 3.725793e-01 -2.6362728 0.1869073 1.610764e-01 3.725793e-01
9  0.06317060 0.4251968 3.981087e-01 -2.7619163 0.1807923 1.692745e-01 3.981087e-01
10 1.32624421 0.7272188 1.143495e+00  0.2823510 0.5288472 8.315712e-01 1.143495e+00

Je recherche une fonction magique qui applique log (y) ~ x ^ 2 + x * z + z aux données et produit:

     df = abs(data.frame(y = rnorm(10),x=rnorm(10),z=rnorm(10)))
> df
            y         x            z
1  0.80805320 2.0371328 7.645385e-01
2  0.45052293 0.9700742 5.456879e-05
3  1.36125062 0.5002969 5.911681e-03
4  1.43985610 0.7149159 2.062861e+00
5  0.31509256 0.4588976 9.477389e-01
6  0.27022582 1.1975979 4.723059e-01
7  0.62058948 0.9114911 2.877264e-01
8  0.07162775 0.4323277 3.725793e-01
9  0.06317060 0.4251968 3.981087e-01
10 1.32624421 0.7272188 1.143495e+00

r

3 commentaires

Jetez un œil à transform ()


Merci. Je viens de vérifier et cela n'aide pas beaucoup. Je vois que la même fonction est appliquée dans le genre lm () mais je ne trouve pas le code exact


model.frame (log (y) ~ I (x ^ 2) + I (x * z) + z, data = df) cela fonctionne, mais vous devez envelopper x * z et x ^ 2 dans le I () sinon vous obtenez les interactions ....


4 Réponses :


2
votes

Je ne suis pas convaincu que ce soit une bonne idée. Il semble assez facile de taper x ^ 2, x * z, ... , et toute tentative d'évaluation de ces formules semble susceptible de laisser certains cas marginaux non pris en compte. Mais voici une façon de procéder.

library(tidyverse)

my_form <- log(y)~x^2+x*z +z

my_form %>% 
  as.character %>% 
  keep(~ . != '~') %>% 
  str_split('\\+') %>% 
  unlist %>% 
  setNames(., .) %>% 
  map_dfc(~ eval(parse(text = .x), df))

# # A tibble: 10 x 4
#    `log(y)`   `x^2 ` ` x * z `   ` z`
#       <dbl>    <dbl>     <dbl>  <dbl>
#  1  0.670   0.109       0.211  0.640 
#  2 -2.32    3.48        1.05   0.561 
#  3 -1.90    1.66        0.0778 0.0604
#  4  0.341   2.46        2.26   1.44  
#  5 -2.09    0.536       0.254  0.347 
#  6  0.133   4.39        1.24   0.590 
#  7  0.291   0.00591     0.0501 0.652 
#  8 -0.00351 0.000674    0.0199 0.766 
#  9 -0.485   0.109       0.0103 0.0314
# 10 -0.495   1.36        0.893  0.765 


0 commentaires

3
votes

En utilisant les entrées de la note à la fin, nous divisons les termes donnant nms dans la première ligne, puis évaluons chacun d'eux donnant la matrice m que nous convertissons en données .frame.

fo <- log(y) ~ x^2 + x * z + z  # input formula

set.seed(123)
df <- abs(data.frame(y = rnorm(10), x = rnorm(10), z = rnorm(10)))

donnant ce bloc de données:

            y         x         z     log(y)        x^2      x * z         z
1  0.56047565 1.2240818 1.0678237 -0.5789695 1.49837625 1.30710356 1.0678237
2  0.23017749 0.3598138 0.2179749 -1.4689046 0.12946599 0.07843039 0.2179749
3  1.55870831 0.4007715 1.0260044  0.4438575 0.16061776 0.41119329 1.0260044
4  0.07050839 0.1106827 0.7288912 -2.6520235 0.01225066 0.08067566 0.7288912
5  0.12928774 0.5558411 0.6250393 -2.0457149 0.30895937 0.34742254 0.6250393
6  1.71506499 1.7869131 1.6866933  0.5394510 3.19305856 3.01397443 1.6866933
7  0.46091621 0.4978505 0.8377870 -0.7745390 0.24785510 0.41709268 0.8377870
8  1.26506123 1.9666172 0.1533731  0.2351205 3.86758304 0.30162620 0.1533731
9  0.68685285 0.7013559 1.1381369 -0.3756352 0.49190010 0.79823906 1.1381369
10 0.44566197 0.4727914 1.2538149 -0.8081945 0.22353172 0.59279292 1.2538149

Remarque

Les entrées sous forme reproductible sont:

nms <- trimws(scan(text = sub("~", "+", format(fo)), what = "", sep = "+", quiet = TRUE))
m <- sapply(nms, function(x) eval(parse(text = x), df))
cbind(df, m)


0 commentaires

1
votes

Une solution de paradigme fonctionnel:

library(tidyverse)

df <- abs(data.frame(y = rnorm(10),x = rnorm(10), z = rnorm(10)))
formula <- "log(y) ~ x ^ 2 + x * z + z"

add_expr_column <- function(df) {
    function(e) {
        df %>% 
            mutate(!!e := eval(parse(text = e))) %>% 
            select(e)
    }
}

formula %>% 
    str_split("~|\\+") %>%
    unlist() %>% 
    map(add_expr_column(df)) %>% 
    bind_cols(df, .)

#            y          x           z      log(y)          x^2        x*z           z1
#1  2.23099710 0.74623401 1.353305848  0.80244861 0.5568652025 1.009882854 1.353305848
#2  1.71320154 0.47955684 1.612452480  0.53836387 0.2299747664 0.773262622 1.612452480
#3  1.15136870 1.24478445 0.988070302  0.14095141 1.5494883309 1.229934549 0.988070302
#4  2.63530469 1.85889324 1.180528845  0.96899881 3.4554840915 2.194477094 1.180528845


0 commentaires

1
votes

Semblable à la solution de @ g-grothendieck mais avec strsplit.

dat <- structure(list(y = c(1.37095844714667, 0.564698171396089, 0.363128411337339, 
0.63286260496104, 0.404268323140999, 0.106124516091484, 1.51152199743894, 
0.0946590384130976, 2.01842371387704, 0.062714099052421), x = c(1.30486965422349, 
2.28664539270111, 1.38886070111234, 0.278788766817371, 0.133321336393658, 
0.635950398070074, 0.284252921416072, 2.65645542090478, 2.44046692857552, 
1.32011334573019), z = c(0.306638594078475, 1.78130843398, 0.171917355759621, 
1.2146746991726, 1.89519346126497, 0.4304691316062, 0.25726938276893, 
1.76316308519478, 0.460097354831271, 0.639994875960119)), row.names = c(NA, 
-10L), class = "data.frame")

fml <- log(y) ~ x^2 + x*z + z

Données em>

s <- strsplit(paste(as.character(fml)[-1], collapse="+"), "\\+")[[1]]
sapply(s, function(s) with(dat, eval(parse(text=s))))
#           log(y)       x^2      x * z          z
#  [1,]  0.3155101 1.70268481 0.40012340 0.3066386
#  [2,] -0.5714639 5.22874715 4.07322072 1.7813084
#  [3,] -1.0129988 1.92893405 0.23876926 0.1719174
#  [4,] -0.4575019 0.07772318 0.33863766 1.2146747
#  [5,] -0.9056765 0.01777458 0.25266972 1.8951935
#  [6,] -2.2431422 0.40443291 0.27375702 0.4304691
#  [7,]  0.4131171 0.08079972 0.07312957 0.2572694
#  [8,] -2.3574739 7.05675540 4.68376414 1.7631631
#  [9,]  0.7023169 5.95587883 1.12285238 0.4600974
# [10,] -2.7691690 1.74269925 0.84486578 0.6399949


0 commentaires