É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
4 Réponses :
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
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
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)
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
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
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 ....