9
votes

Comment sous-ensembles de dataframe sur la base d'un critère "différent de" appliqué à un grand nombre de colonnes?

Je suis nouveau dans R et j'essaie actuellement de sous-regrouper mes données en fonction de mes critères d'exclusion prédéfinis pour l'analyse. J'essaie actuellement de supprimer tous les cas de démence, comme codé par la CIM-10. Le problème est qu'il existe plusieurs variables contenant des informations sur l'état de santé de chaque individu (~ 70 variables), même si comme elles sont codées de la même manière, la même condition peut être appliquée à toutes.

Quelques données simulées:

     ID disease_code_1 disease_code_2 disease_code_3
1  1001           I802           A071           H250
2  1002           H356             NA             NA
4  1004           D235             NA           I802
5  1005           B178             NA             NA
8  1008           C761             NA             NA
11 1011           J679           A045           D352

Ici, j'essaie de supprimer tous les cas qui ont un "code de démence" dans l'une des variables "code_maladie". p>

Error in 2:4 != "F023" | "G20" : 
  operations are possible only for numeric, logical or complex types

L'erreur que je reçois est:

#Remove cases with dementia from dataframe (e.g. F023, G20)
Newdata_df <- subset(df, (2:4 != "F023"|"G20"|"F009"|"F002"|"F001"|"F000"|"F00"|    
                    "G309"| "G308"|"G301"|"G300"|"G30"| "F01"|"F018"|"F013"|
                    "F012"| "F011"| "F010"|"F01"))

Idéalement, le dataframe sous-défini ressemblerait à ceci:

XXX

Je sais qu'il y a une erreur dans mon code même si je ne sais pas exactement comment la corriger. J'ai essayé plusieurs autres méthodes (en utilisant dplyr) mais je n'ai pas eu de chance jusqu'à présent.

Toute aide est grandement appréciée!


2 commentaires

Vous devez remodeler vos données au format long. Cela vous facilitera la vie (et l'analyse).


Et gardez le package CRAN icd à l'esprit pour conserver votre santé mentale . De nombreux problèmes similaires à celui-ci bénéficient ou nécessitent l'application de cartes de comorbidité, ce que icd fait très soigneusement et rapidement en utilisant des cartes de maladies bien validées et largement citées. Cela ne répond pas à votre question, mais l'utilisation de cette technique aurait pu éviter ce problème, en fonction de ce que vous aviez déjà fait et de ce que vous alliez faire avec les données.


6 Réponses :


3
votes

Que diriez-vous de ceci:

> df[apply(df[-1], 1, function(x) {!any(x %in% dementia)}),]
     ID disease_code_1 disease_code_2 disease_code_3
1  1001           I802           A071           H250
2  1002           H356             NA             NA
4  1004           D235             NA           I802
5  1005           B178             NA             NA
8  1008           C761             NA             NA
11 1011           J679           A045           D352

Modifier:

Une solution encore plus élégante, grâce à @ Ronan Shah:

> dementia <- c("F023", "G20", "F009", "F002", "F001", "F000", "F00", "G309", "G308",
+               "G301", "G300", "G30", "F01", "F018", "F013", "F012", "F011", "F010", "F01")
> 
> dementia <- apply(sapply(df[, -1], function(x) {x %in% dementia}), 1, any)
> 
> df[!dementia,]
     ID disease_code_1 disease_code_2 disease_code_3
1  1001           I802           A071           H250
2  1002           H356             NA             NA
4  1004           D235             NA           I802
5  1005           B178             NA             NA
8  1008           C761             NA             NA
11 1011           J679           A045           D352
> 

J'espère que cela vous aidera.


1 commentaires

@ Ronan Shah Nice! C'est une solution plus élégante. Vous devriez le poster.



4
votes

Nous pouvons créer un vecteur avec les codes à supprimer et utiliser rowSums pour supprimer, c'est-à-dire

     ID disease_code_1 disease_code_2 disease_code_3
1  1001           I802           A071           H250
2  1002           H356             NA             NA
4  1004           D235             NA           I802
5  1005           B178             NA             NA
8  1008           C761             NA             NA
11 1011           J679           A045           D352

ce qui donne,

codes_to_remove <- c("F023", "G20", "F009", "F002", "F001", "F000", "F00", "G309", "G308",
                "G301", "G300", "G30", "F01", "F018", "F013", "F012", "F011", "F010", "F01")

df[rowSums(sapply(df[-1], `%in%`, codes_to_remove)) == 0,]


0 commentaires

3
votes

Une possibilité dplyr pourrait être:

df %>%
 filter_at(vars(contains("disease_code")), all_vars(! . %in% c("F023","G20","F009","F002","F001","F000","F00",    
            "G309", "G308","G301","G300","G30", "F01","F018","F013",
            "F012", "F011", "F010","F01")))

Dans ce cas, il vérifie si l'une des colonnes 2: 4 contient l'un des codes donnés. p>

Ou:

df %>%
 filter_at(vars(2:4), all_vars(! . %in% c("F023","G20","F009","F002","F001","F000","F00",    
            "G309", "G308","G301","G300","G30", "F01","F018","F013",
            "F012", "F011", "F010","F01")))

    ID disease_code_1 disease_code_2 disease_code_3
1 1001           I802           A071           H250
2 1002           H356             NA             NA
3 1004           D235             NA           I802
4 1005           B178             NA             NA
5 1008           C761             NA             NA
6 1011           J679           A045           D352

Dans ce cas, il vérifie si l'une des colonnes portant le nom maladie_code contient l'un des codes donnés.


1 commentaires

Merci à tous pour vos suggestions! J'apprécie que vous ayez également expliqué ce que votre code suggéré fait @tmfmnk - vraiment utile!



3
votes

Comme mentionné dans les commentaires de @docendo discimus, nous pouvons convertir la trame de données au format long en utilisant rassembler , group_by ID et sélectionner uniquement ceux ID s qui ne contiennent pas de dementia_code , puis répartissez ces derniers vers un format large.

dementia_code <- c("F023", "G20", "F009", "F002", "F001", "F000", "F00", "G309", 
"G308","G301", "G300", "G30", "F01", "F018", "F013", "F012", "F011", "F010", "F01")

library(tidyverse)

df %>%
   gather(key, value, -ID) %>%
   group_by(ID) %>%
   filter(!any(value %in% dementia_code)) %>%
   spread(key, value)

#   ID disease_code_1 disease_code_2 disease_code_3
#  <dbl> <chr>          <chr>          <chr>         
#1  1001 I802           A071           H250          
#2  1002 H356           NA             NA            
#3  1004 D235           NA             I802          
#4  1005 B178           NA             NA            
#5  1008 C761           NA             NA            
#6  1011 J679           A045           D352          


3 commentaires

Pourquoi charger tout tidyverse ? N'est-ce pas simplement tidyr et dplyr ?


@Dunois oui, ça l'est. J'ai l'habitude de tout charger par défaut: P


Nous pourrions également le faire en utilisant un anti_join tel que Newdata_df <- df%>% anti_join (df%>% rassembl (DiseaseCodeNumber, CodeValue, -ID)%>% filter (CodeValue% in % c ("F023", "G20", "F009", "F002", "F001", "F000", "F00", "G309", "G308", "G301", "G300", "G30" , "F01", "F018", "F013", "F012", "F011", "F010", "F01")), par = "ID")



2
votes

Une version de boucle pour avec base R, au cas où vous préférez.

df <- data.frame(ID = c(1001, 1002, 1003, 1004, 1005,1006,1007,1008,1009,1010,1011),
                disease_code_1 = c('I802','H356','G560','D235','B178','F011','F023','C761','H653','A049','J679'),
                disease_code_2 = c('A071','NA','G20','NA','NA','A049','NA','NA','G300','G308','A045'),
                disease_code_3 = c('H250','NA','NA','I802','NA','A481','NA','NA','NA','NA','D352'), stringsAsFactors = FALSE)

dementia_codes <- c("F023", "G20", "F009", "F002", "F001", "F000", "F00", "G309", "G308", "G301", "G300", "G30", "F01", "F018", "F013", "F012", "F011", "F010", "F01")

new_df <- df[0,]

for(i in 1:nrow(df)){
  currRow <- df[i,]
  if(any(dementia_codes %in% as.character(currRow)) == FALSE){
    new_df <- rbind(new_df, currRow)
  }
}

new_df
#      ID disease_code_1 disease_code_2 disease_code_3
# 1  1001           I802           A071           H250
# 2  1002           H356             NA             NA
# 4  1004           D235             NA           I802
# 5  1005           B178             NA             NA
# 8  1008           C761             NA             NA
# 11 1011           J679           A045           D352


0 commentaires

3
votes

Nous pouvons utiliser melt / dcast de data.table

dementia_codes <- c("F023", "G20", "F009", "F002", "F001", "F000", 
  "F00", "G309", "G308", "G301", "G300", "G30", "F01", "F018", "F013", 
   "F012", "F011", "F010", "F01")

Ou cela peut être fait de manière plus compacte dans base R sans remodelage

df[!Reduce(`|`, lapply(df[-1], `%in%` , dementia_codes)),]
 #   ID disease_code_1 disease_code_2 disease_code_3
#1  1001           I802           A071           H250
#2  1002           H356             NA             NA
#4  1004           D235             NA           I802
#5  1005           B178             NA             NA
#8  1008           C761             NA             NA
#11 1011           J679           A045           D352

données

library(data.table)
dcast(melt(setDT(df), id.var = 'ID')[,
     if(!any(value %in% dementia_codes)) .SD, .(ID)], ID ~ variable)
#    ID disease_code_1 disease_code_2 disease_code_3
#1: 1001           I802           A071           H250
#2: 1002           H356             NA             NA
#3: 1004           D235             NA           I802
#4: 1005           B178             NA             NA
#5: 1008           C761             NA             NA
#6: 1011           J679           A045           D352


0 commentaires