J'ai une base de données sur les expositions aux produits chimiques qui ressemble à ceci:
Error in cut.default(., chem_dat$.x, breaks = c(-Inf, quantile(control_chem_dat$.x, : 'x' must be numeric
Je dois convertir les valeurs continues de chacun des produits chimiques en catégories basées sur la valeur d'exposition. La distribution des valeurs est très biaisée, avec de nombreuses valeurs 0 et quelques valeurs très élevées. Ces coupes doivent être basées sur le sous-ensemble de l'ensemble de données qui contient des contrôles, qui ressemble à celui ci-dessus. Le résultat devrait ressembler à ceci:
chem_cut <- map(chem_names, ~ chem_dat %>% cut( chem_dat$.x, breaks=c(-Inf, quantile(control_chem_dat$.x , probs=c(0.5,0.75), na.rm=TRUE), Inf)) %>% mutate(!!str_c(.x, "cut", sep = "_") := .x))
J'ai utilisé la fonction de coupe comme ceci pour chaque produit chimique individuel:
chem_dat$chem_1 <- cut(chem_dat$chem_1 , breaks=c(-Inf, quantile(control_chem_dat$chem_1 , probs=c( 0.5,0.75), na.rm=TRUE), Inf))
Je veux pouvoir faire ceci, ou quelque chose comme ça, à toutes les colonnes à l'intérieur d'une fonction afin de ne pas avoir à écrire ce que j'ai plus de 524 fois. Je ne peux pas utiliser la fonction ntile car elle pose des problèmes avec des colonnes extrêmement 0 gonflées.
Voici ce que j'ai essayé:
chem_names XXX
Cela me donne l'erreur
chem1_cut chem2_cut chem3_cut ... (-inf, 0.1] (0.1, 12.1] (0.1, 12.1] (0.1, 12.1] (12.1, inf] NA (0.1, 12.1] (0.1, 12.1] (-inf, 0.1]
Comment puis-je corriger cette fonction pour faire ce que je veux? Ou, y a-t-il une meilleure façon de faire cette tâche avec une sorte de package ou quelque chose?
Merci pour votre aide!
3 Réponses :
Essayez cette solution base R
. On considère que chem_dat
et control_chem_dat
sont des dataframes séparés. Dans cet exemple, j'ai défini les mêmes valeurs mais vous pouvez les remplacer. En espérant que cela peut vous aider:
#Data chem_dat <- structure(list(chem1 = c(0.06, 0.7, 0.4), chem2 = c(6.8, 24.3,2.9), chem3 = c(0.3, NA, 0.03), chem524 = c(0.2, 0.7, 1.6)), class = "data.frame", row.names = c(NA,-3L)) #Data control_chem_dat <- structure(list(chem1 = c(0.06, 0.7, 0.4), chem2 = c(6.8, 24.3,2.9), chem3 = c(0.3, NA, 0.03), chem524 = c(0.2, 0.7, 1.6)), class = "data.frame", row.names = c(NA,-3L)) #Function cut_func <- function(x,y) { z <- cut(y,breaks=c(-Inf, quantile(x , probs=c( 0.5,0.75), na.rm=TRUE), Inf)) return(z) } #Apply Result <- as.data.frame(mapply(cut_func,control_chem_dat,chem_dat)) chem1 chem2 chem3 chem524 1 (-Inf,0.4] (-Inf,6.8] (0.232, Inf] (-Inf,0.7] 2 (0.55, Inf] (15.6, Inf] <NA> (-Inf,0.7] 3 (-Inf,0.4] (-Inf,6.8] (-Inf,0.165] (1.15, Inf]
C'est une bonne solution, mais je ne sais pas si les ruptures doivent être basées sur les quantiles d'un autre df control_chem_dat
@starja il prend les quantiles en fonction des valeurs de chaque colonne. Il n'y a pas d'autre dataframe, juste celui que vous avez.
C'était aussi ma première pensée, mais dans le code de @Justin Andrew, il utilise en fait les quantiles de control_chem_dat
pour les ruptures de données dans chem_dat
@starja Dans ce cas, la deuxième trame de données doit être fournie. Mais je comprends que vous ne devez utiliser qu'un seul dataframe.
Vous pouvez utiliser lapply
pour générer l'index de colonne et appliquer la fonction à chaque colonne de votre chem_dat
. L'utilisation de l'index présente l'avantage de pouvoir également indexer control_chem_dat
(étant donné que les colonnes sont dans le même ordre). Cela génère une liste avec une entrée pour chaque colonne, vous pouvez utiliser cbind
pour le lier à un data.frame:
chem_cut_list <- lapply(seq_len(ncol(chem_dat)), 2, function(i) { cut(chem_dat[, i] , breaks=c(-Inf, quantile(control_chem_dat[, i], probs=c( 0.5,0.75), na.rm=TRUE), Inf)) }) chem_cut <- do.call("cbind", chem_cut_list)
Dans purrr
, il y a une fonction map2 * pour parcourir plusieurs arguments simultanément. Lorsqu'un data.frame est fourni à map * ()
, il parcourra les colonnes. Essayons-le avec un exemple de jeu de données:
map2_dfc(control_chem_dat,chem_dat,cut_y_by_x) # A tibble: 5 x 3 chem1 chem2 chem3 <fct> <fct> <fct> 1 (0.453, Inf] (-Inf,0.27] (0.432, Inf] 2 (0.403,0.453] (0.351, Inf] (-Inf,0.383] 3 (0.453, Inf] (0.351, Inf] (0.432, Inf] 4 (0.403,0.453] (0.27,0.351] (0.432, Inf] 5 (0.453, Inf] (-Inf,0.27] (-Inf,0.383]
Écrivez une fonction pour effectuer cette tâche, étant donné x
, coupez y
comme vous l'avez:
mapply(cut_y_by_x,control_chem_dat,chem_dat)
Dans la base R, nous faisons ceci (pour que vous puissiez voir le parallèle dans purrr):
cut_y_by_x = function(x,y){ cut(y,c(-Inf, quantile(x , probs=c(0.5,0.75), na.rm=TRUE),+Inf)) }
Faisons ceci dans purrr:
library(purrr) set.seed(555) control_chem_dat = data.frame(matrix(runif(10*3,min=0,max=0.5),ncol=3)) colnames(control_chem_dat) = paste0("chem",1:3) chem_dat = data.frame(matrix(runif(5*3,min=0,max=1),ncol=3)) colnames(chem_dat) = paste0("chem",1:3)
chem_dat
etcontrol_chem_dat
ne sont pas les mêmes data.frames, non? si tel est le cas, veuillez fournir un exemple decontrol_chem_dat
Oui, control_chem_dat est un data.frame différent avec exactement le même format. Merci pour cette suggestion.