2016-05-28 11 views
5
snp1 <- c("AA", "AT", "AA", "TT", "AA", "AT", "AA", "AA", "AA", "AT") 
snp2 <- c("GG", "GC", "GG", "CC", "CC", "GC", "GG", "GG", "GG", "GC") 
df1 <- data.frame(snp1, snp2) 

num1 <- c(1, 2, 1, 3, 1, 2, 1, 1, 1, 2) 
num2 <- c(1, 2, 1, 3, 3, 2, 1, 1, 1, 2) 
df2 <- data.frame(num1, num2) 

Odbywa się to w R. Mam obiekt df1, który chcę przekonwertować na df2. Dla każdej kolumny w df1 najpopularniejsza wartość jest konwertowana na 1, druga najczęściej używana wartość to 2 itd. Jak mogę to zrobić wydajnie?Konwertuj ramkę danych z genotypów snp w macierzy numerycznej

+0

'data.frame (lapply (DF1, function (x) {as.numeric (współczynnik (x, poziom = Nazwy (porządek (-table (x)))))})) ' – alistaire

Odpowiedz

3

najczęstsza wartość jest konwertowana na 1, druga najczęściej używana wartość to 2 itd.

Można użyć table, sort, factor:

convert <- function(x) as.integer(factor(x, levels = names(sort(-table(x))))) 

num1 <- convert(df1$snp1) 
num2 <- convert(df$2snp2) 

zastosować to do wszystkich kolumn w poręczny sposób?

Zastosowanie lapply:

df2 <- as.data.frame(lapply(df1, FUN = convert)) 

Dyskusja:

@thelatemail wspomniano możliwość zastosowania match(). Jego użycie levels() zakłada, że ​​wszystkie kolumny df1 są łatwo czynnikami. Często jest to prawdą, chyba że niektórzy, jak ja, ustawili options(stringsAsFactors = FALSE) w pliku startowym R. Zamieniłbym levels() na names(), więc jego pomysł będzie działał zarówno dla wejścia łańcuchowego, jak i wejściowego.

convert2 <- function(x) { 
    tab <- table(x) 
    match(x, names(tab)[order(-tab)]) 
    } 

Nasze pierwsze pytanie brzmi, jest znacznie szybszy niż convert2()convert()?

Definiujemy funkcję zabawka dla pomiaru wydajności pomiędzy dwoma funkcjami:

timing <- function(n, rep, FACTOR = FALSE, FUN1, FUN2) { 
    ## sample data 
    x <- c("AA", "AT", "TT")[sample(1:3, n, replace = TRUE)] 
    if (FACTOR) x <- factor(x) 
    ## method 1: as.integer(factor()) 
    t1 <- system.time(for (k in 1:rep) {tmp <- FUN1(x); tmp <- FUN1(x); tmp <- FUN1(x); tmp <- FUN1(x)}) 
    ## method 2: match() 
    t2 <- system.time(for (k in 1:rep) {tmp <- FUN2(x); tmp <- FUN2(x); tmp <- FUN2(x); tmp <- FUN2(x)}) 
    ## timing summary 
    cat("FUN1\n"); print(t1) 
    cat("FUN2\n"); print(t2) 
    } 

Dla wejścia ciąg znaków mamy:

> timing(n = 20000, rep = 1000, FACTOR = FALSE, FUN1 = convert, FUN2 = convert2) 
FUN1 ## convert(), using as.integer(factor()) 
    user system elapsed 
18.772 0.212 19.052 
FUN2 ## convert2(), using match() 
    user system elapsed 
17.792 0.100 17.920 

Dla wejścia czynnika, mamy:

> timing(n = 20000, rep = 1000, FACTOR = TRUE, FUN1 = convert, FUN2 = convert2) 
FUN1 ## convert(), using as.integer(factor()) 
    user system elapsed 
17.180 0.144 17.384 
FUN2 ## convert2(), using match() 
    user system elapsed 
15.500 0.168 15.693 

A więc:

  • gdy dane wejściowe są czynnikami, obie metody są marginalnie szybsze;
  • convert2() jest o 5% - 10% szybsza niż convert1().

Teraz ograniczmy to, że mamy czynnik wejściowy, możemy sprawić, że convert2() będzie szybszy. Rozważ:

## only works for factor input!! 
convert3 <- function(x) { 
    tab <- table(x) 
    match(as.integer(x), (seq_along(tab))[order(-tab)]) 
    } 

Tutaj użyliśmy dopasowania liczb całkowitych.Porównaj convert2() i convert3():

> timing(n = 20000, rep = 1000, FACTOR = TRUE, FUN1 = convert2, FUN2 = convert3) 
FUN1 ## convert2(), using string match 
    user system elapsed 
15.168 0.156 15.351 
FUN2 ## convert3(), using integer match 
    user system elapsed 
14.032 0.116 14.174 
6

wariacja na temat:

lapply(df1, function(x) match(x, levels(x)[order(-table(x))])) 
#$snp1 
# [1] 1 2 1 3 1 2 1 1 1 2 
# 
#$snp2 
# [1] 1 2 1 3 3 2 1 1 1 2 
Powiązane problemy