Nidificato se else istruzioni su un numero di colonne

Ho un grande data.frame cui le prime tre colonne contengono informazioni su un marcatore . Le colonne rimanenti sono di tipo numerico per quel marcatore in ogni individuo. Ogni individuo ha tre colonne. Il set di dati appare come segue:

  marker alleleA alleleB X818 X818.1 X818.2 X345 X345.1 X345.2 X346 X346.1 X346.2 1 kgp5209280_chr3_21902067 TA 0.0000 1.0000 0.0000 1.0000 0.0000 0.0000 0.0000 1.0000 0.0000 2 chr3_21902130_21902131_A_T AT 0.8626 0.1356 0.0018 0.7676 0.2170 0.0154 0.8626 0.1356 0.0018 3 chr3_21902134_21902135_T_C TC 0.6982 0.2854 0.0164 0.5617 0.3749 0.0634 0.6982 0.2854 0.0164 

Cioè, per ogni marcatore (riga), ogni individuo ha tre valori, uno in ogni colonna.

Voglio creare un nuovo data.frame che abbia tutte le stesse file dell’originale, ma solo una colonna per ogni individuo. In una colonna per ogni individuo voglio il valore dei tre per ogni individuo che è maggiore di 0.8. Se nessun valore è maggiore di 0.8, allora voglio stampare NA. Ad esempio, nel set di dati che ho dato per la prima riga vorrei il secondo valore per 818 (1.0000) e il primo valore per 345 (1.0000). Nella seconda riga, voglio il primo valore per 818 (0.8626), e per 345 nessuno dei valori è superiore a 0.8, quindi voglio che NA sia stampato e così via. Il nuovo set di dati sarebbe quindi simile a questo:

  marker alleleA alleleB X818 X345 1 kgp5209280_chr3_21902067 TA 1.0000 1 2 chr3_21902130_21902131_A_T AT 0.8626 NA 

Ho cercato di usare if/else statement, sulla falsariga di if [, 4] > 0.8 then [, 4], else... comunque non sembra darmi quello che voglio, e vorrei anche per eseguire il loop di questo comando in modo che non lo faccia solo per un individuo nelle prime tre colonne ma per tutte le colonne.

Qualsiasi aiuto sarebbe apprezzato! Grazie in anticipo.

Modifica: soluzione aggiornata utilizzando i metodi di fusione veloce / dcast implementati nelle versioni data.table > = 1.9.0. Vai qui per maggiori informazioni.

 require(data.table) require(reshape2) dt <- as.data.table(df) # melt data.table dt.m <- melt(dt, id=c("marker", "alleleA", "alleleB"), variable.name="id", value.name="val") dt.m[, id := gsub("\\.[0-9]+$", "", id)] # replace `.[0-9]` with nothing # aggregation dt.m <- dt.m[, list(alleleA = alleleA[1], alleleB = alleleB[1], val = max(val)), keyby=list(marker, id)][val <= 0.8, val := NA] # casting back dt.c <- dcast.data.table(dt.m, marker + alleleA + alleleB ~ id) # marker alleleA alleleB X345 X346 X818 # 1: chr3_21902130_21902131_A_T AT NA 0.8626 0.8626 # 2: chr3_21902134_21902135_T_C TC NA NA NA # 3: kgp5209280_chr3_21902067 TA 1 1.0000 1.0000 

Soluzione 1: Probabilmente non è il modo migliore, ma questo è quello che potrei pensare al momento:

 mm <- t(apply(df[-(1:3)], 1, function(x) tapply(x, gl(3,3), max))) mode(mm) <- "numeric" mm[mm < 0.8] <- NA # you can set the column names of mm here if necessary out <- cbind(df[, 1:3], mm) # marker alleleA alleleB 1 2 3 # 1 kgp5209280_chr3_21902067 TA 1.0000 1 1.0000 # 2 chr3_21902130_21902131_A_T AT 0.8626 NA 0.8626 # 3 chr3_21902134_21902135_T_C TC NA NA NA 

gl(3,3) dà un fattore con valori 1,1,1,2,2,2,3,3,3 con livelli 1,2,3 . Cioè, tapply prenderà i valori x 3 alla volta e otterrà il loro max (primo 3, prossimo 3 e ultimo 3). E apply invia ciascuna riga una per una.


Soluzione 2: una soluzione data.table con melt e cast all'interno di data.table senza usare reshape2 o reshape2 :

 require(data.table) dt <- data.table(df) # melt your data.table to long format dt.melt <- dt[, list(id = names(.SD), val = unlist(.SD)), by=list(marker, alleleA, alleleB)] # replace `.[0-9]` with nothing dt.melt[, id := gsub("\\.[0-9]+$", "", id)] # get max value grouping by marker and id dt.melt <- dt.melt[, list(alleleA = alleleA[1], alleleB = alleleB[1], val = max(val)), keyby=list(marker, id)][val <= 0.8, val := NA] # edit mnel (use setattr(,'names') to avoid copy by `names<-` within `setNames` dt.cast <- dt.melt[, as.list(setattr(val,'names', id)), by=list(marker, alleleA, alleleB)] # marker alleleA alleleB X345 X346 X818 # 1: chr3_21902130_21902131_A_T AT NA 0.8626 0.8626 # 2: chr3_21902134_21902135_T_C TC NA NA NA # 3: kgp5209280_chr3_21902067 TA 1 1.0000 1.0000 

Penso che sia meglio mettere i tuoi dati nel formato lungo. Ecco una soluzione basata sul pacchetto reshape2 , forse simile alla seconda soluzione @Arun ma sintatticamente diversa

 library(reshape2) dat.m <- melt(dat,id.vars=1:3) dat.m$variable <- gsub('[.].*','',dat.m$variable) dcast(dat.m,...~variable,fun.aggregate=function(x){ res <- NA_real_ if(length(x) > 0 && max(x)> 0.8) res <- max(x) res }) marker alleleA alleleB X345 X346 X818 1 chr3_21902130_21902131_A_T AT NA 0.8626 0.8626 2 chr3_21902134_21902135_T_C TC NA NA NA 3 kgp5209280_chr3_21902067 TA 1 1.0000 1.0000 

Ecco il mio approccio usando la funzione pmax . Nota che questo ti darà il massimo se ci sono due o più valori sopra 0.8 per ogni individuo:

 df <- read.table(textConnection(" marker alleleA alleleB X818 X818.1 X818.2 X345 X345.1 X345.2 X346 X346.1 X346.2 1 kgp5209280_chr3_21902067 TA 0.0000 1.0000 0.0000 1.0000 0.0000 0.0000 0.0000 1.0000 0.0000 2 chr3_21902130_21902131_A_T AT 0.8626 0.1356 0.0018 0.7676 0.2170 0.0154 0.8626 0.1356 0.0018 3 chr3_21902134_21902135_T_C TC 0.6982 0.2854 0.0164 0.5617 0.3749 0.0634 0.6982 0.2854 0.0164"), header=TRUE) #data.table solution library(data.table) DT <- as.data.table(df) DT[, M818 := ifelse(pmax(X818, X818.1, X818.2) > 0.8, pmax(X818, X818.1, X818.2), NA)] DT[, M345 := ifelse(pmax(X345, X345.1, X345.2) > 0.8, pmax(X345, X345.1, X345.2), NA)] DT[, M346 := ifelse(pmax(X346, X346.1, X346.2) > 0.8, pmax(X346, X346.1, X346.2), NA)] #Base R solution df$M818 <- ifelse(pmax(df$X818, df$X818.1, df$X818.2) > 0.8, pmax(df$X818, df$X818.1, df$X818.2), NA) df$M345 <- ifelse(pmax(df$X345, df$X345.1, df$X345.2) > 0.8, pmax(df$X345, df$X345.1, df$X345.2), NA) df$M346 <- ifelse(pmax(df$X346, df$X346.1, df$X346.2) > 0.8, pmax(df$X346, df$X346.1, df$X346.2), NA) 

Se vuoi eliminare le altre colonne, digita:

 DT[, list(marker, alleleA, alleleB, M818, M345, M346)] marker alleleA alleleB M818 M345 M346 1: kgp5209280_chr3_21902067 TA 1.0000 1 1.0000 2: chr3_21902130_21902131_A_T AT 0.8626 NA 0.8626 3: chr3_21902134_21902135_T_C TC NA NA NA 

Questa è un’altra ansible soluzione. Tutte le soluzioni sopra sono valide.

La mia soluzione è creare una funzione per la distinzione tra maiuscole e minuscole senza l’uso di una nuova libreria. È piuttosto lungo ed è ansible compattare, ma è utile vedere ogni passaggio per capire come funziona la funzione.

 olddf <- data.frame(marker = c("kgp5209280_chr3_21902067", "chr3_21902130_21902131_A_T", "chr3_21902134_21902135_T_C"), alleleA = c("T","A","T"), alleleB = c("A","T","C"), X818 = c(0.0000,0.8626,0.6982), X818.1 = c(1.0000,0.1356,0.2854), X818.2 = c(0.0000,0.0018,0.0164), X345 = c(1.0000,0.7676, 0.5617), X345.1 = c(0.0000, 0.2170, 0.3749), X345.2 = c(0.0000, 0.0154, 0.0634), X346 = c(0.0000, 0.8626, 0.6982), X346.1 = c(1.0000,0.1356, 0.2854), X346.2 = c(0.0000, 0.0018, 0.0164)) mergeallele <- function(arguments,threshold = 0.8){ n <- nrow(arguments) # Creation of a results object as an empty list of length NROW # speed for huge data.frame new.lst <- vector(mode="list", n) for (i in 1:n){ marker_row <- arguments[i,] colvalue.4 <- NaN if (max(marker_row[,c(4:6)]) < threshold){ colvalue.4 <- max(marker_row[,c(4:6)]) } colvalue.5 <- NaN if (max(marker_row[,c(7:9)]) < threshold){ colvalue.5 <- max(marker_row[,c(7:9)]) } colvalue.6 <- NaN if (max(marker_row[,c(10:12)]) < threshold){ colvalue.6 <- max(marker_row[,c(10:12)]) } new.lst[[i]] <- data.frame(marker_row[,1], marker_row[,2], marker_row[,3], colvalue.4, colvalue.5, colvalue.6) } new.df <- as.data.frame(do.call("rbind",new.lst)) names(new.df) <- c(colnames(arguments)[1], colnames(arguments)[2], colnames(arguments)[3], colnames(arguments)[4], colnames(arguments)[7], colnames(arguments)[10]) return(new.df) } newdf <- mergeallele(olddf) marker alleleA alleleB X818 X345 X346 1 kgp5209280_chr3_21902067 TA NaN NaN NaN 2 chr3_21902130_21902131_A_T AT NaN 0.7676 NaN 3 chr3_21902134_21902135_T_C TC 0.6982 0.5617 0.6982 

di:

 threshold = 0.8 

è ansible impostare il valore di soglia (es: 0.8) per evitare di cambiare la variabile all'interno della funzione

 new.lst <- vector(mode="list", n) 

è ansible creare una lista vuota di lunghezza del vecchio data.frame e gli elementi della lista vengono poi gradualmente riempiti con i risultati del ciclo (molto più velocemente). Guarda la velocità del test da questo blog