2015-12-14 3 views
1

Je rencontre un problème avec une tâche particulière de mon code. J'ai une trame de données commesous-ensemble de trame de données en fonction de plusieurs conditions

n <- 6 
set.seed(123) 
df <- data.frame(x=paste0("x",seq_along(1:n)), A=sample(c(-2:2),n,replace=TRUE), B=sample(c(-1:3),n,replace=TRUE)) 
# 
# x A B 
# 1 x1 -1 1 
# 2 x2 1 3 
# 3 x3 0 1 
# 4 x4 2 1 
# 5 x5 2 3 
# 6 x6 -2 1 

et un arbre de décision

A>0;Y;Y;N;N 
B>1;Y;N;Y;N 
C;1;2;2;1 

que je charge par

dt <- read.csv2("tmp.csv", header=FALSE) 

Je voudrais créer une boucle pour toutes les combinaisons possibles de (A> 0) et (B> 1) et définissez la valeur C sur la colonne x du sous-ensemble qui satisfait cette condition. Alors, voici ce que je l'ai fait

nr <- 3 
nc <- 5 

cond <- dt[1:(nr-1),1,drop=FALSE] 
rule <- dt[nr,1,drop=FALSE] 

subdf <- vector(mode="list",2^(nr-1)) 

for (i in 2:nc) { 
    check <- paste0("") 
    for (j in 1:(nr-1)) { 
    case <- paste0(dt[j,1]) 
    if (dt[j,i]=="N") 
     case <- paste0("!",case) 
    check <- paste0(check, "(", case, ")") 

    if (j<(nr-1)) 
     check <- paste0(check, "&") 

    } 

    subdf[i] <- subset(df,check) 
    subdf[i]$C <- dt[nr,i] 

} 
unlist(subdf) 

malheureusement, je suis une erreur en utilisant comme sous-ensemble de cela, il ne peut pas analyser les conditions de mes instructions de chaîne. que devrais-je faire?

+0

Le problème sera-t-il plus important que cela, ou vérifiez-vous seulement a et b? – Heroka

+0

Oui, le problème est plus grand que cela, mais je voulais le simplifier et le généraliser pour d'autres personnes. était-ce mal? – Stefano

+0

Je vérifiais juste. Vous n'avez pas du tout tort (vous avez raison), donc une solution devrait être généralisable à un nombre arbitraire de règles. – Heroka

Répondre

1

Votre problème est de créer le sous-ensemble: les commandes du sous-ensemble attend un booléen et vous lui avez donné une chaîne. ('vérifier'). Donc la solution la plus simple ici est d'ajouter une «analyse». Je pense qu'il ya une façon plus élégante de résoudre ce problème et j'espère venir someone'll le long et le faire, mais vous pouvez fixer la dernière partie de votre code avec les éléments suivants

mysubset <- subset(df,with(df,eval(parse(text=check)))) 
    if(nrow(mysubset)>0){ 
    mysubset$C <- dt[nr,i] 
    } 
    subdf[[i]]<-mysubset 

J'ai ajouté l'analyse syntaxique/eval part pour générer un vecteur de booléens pour ne sous-traiter que les cas 'TRUE', et ajouté une vérification pour savoir si C pourrait être ajouté (donnera une erreur s'il n'y a pas de lignes). Sur la base de la réponse précédente, j'ai trouvé une manière plus élégante/pratique de générer un vecteur de règles combinées, puis de les appliquer toutes aux données, en utilisant apply/lapply.

##create list of formatted rules 

#format each 'building' block separately, 
#based on rows in 'dt'. 
part_conditions <- apply(dt[-nrow(dt),],MARGIN=1,FUN=function(x){ 
    res <- sprintf("(%s%s)", ifelse(x[-1]=="Y","","!"), x[1]) 
}) 

# > part_conditions 
# 1  2  
# [1,] "(A>0)" "(B>1)" 
# [2,] "(A>0)" "(!B>1)" 
# [3,] "(!A>0)" "(B>1)" 
# [4,] "(!A>0)" "(!B>1)" 

#combine to vector of conditions 
conditions <- apply(part_conditions, MARGIN=1,FUN=paste, collapse="&") 

# > conditions 
# [1] "(A>0)&(B>1)" "(A>0)&(!B>1)" "(!A>0)&(B>1)" "(!A>0)&(!B>1)" 

#for each condition, test in data wheter condition is 'T' 
temp <- sapply(conditions, function(rule){ 
    return(with(df, eval(parse(text=rule)))) 
} 
) 


rules <- as.numeric(t(dt[nrow(dt),-1])) 

#then find which of the (in this case) four is 'T', and put the appropriate rule 
#in df 
df$C <- rules[apply(temp,1,which)] 
> df 
    x A B C 
1 x1 -1 1 1 
2 x2 1 3 1 
3 x3 0 1 1 
4 x4 2 1 2 
5 x5 2 3 1 
6 x6 -2 1 1 
+0

exactement ce que je cherchais !!! également le contrôle pour aucun sous-ensemble de ligne. Je ne sais vraiment pas comment te remercier! alors oui, s'il y avait une solution plus élégante pour la commande de parsing, ce serait génial, mais ça suffit déjà. Je voudrais simplement ajouter 'finaldf <- data.frame (x = c(), A = c(), B = c(), C = c())' hors de la boucle et remplacer 'subdf [[i ]] <- mysubset' par 'finaldf <- rbind (finaldf, mysubset)' à l'intérieur de l'instruction if. – Stefano

+0

J'ai une idée pour une solution plus élégante, travaillera dessus plus tard aujourd'hui – Heroka

+0

ok merci d'avance. faites le moi savoir. – Stefano