2014-07-19 2 views
2

У меня есть несколько data.frames, каждый из которых имеет коэффициент. Я хочу убедиться, что все они используют одни и те же уровни. Каков правильный способ сделать это?Лучший способ сделать коэффициенты уровней однородными по нескольким кадрам данных

В приведенном ниже коде вы увидите, что я переназначаю коэффициент для каждого случая, используя уровни из общего набора уровней с небольшой функцией changeLevels. Я бы ожидал, что есть лучший способ сделать это.

set.seed(1234) 
b<-round(runif(100,1,10),digits=2) 
set.seed(2345) 
b2<-round(runif(100,11,20),digits=2) 
set.seed(3456) 
b3<-round(runif(50,15,18),digits=2) 

#.. all potential levels 
bt<-factor(sort(c(b,b2,b3))) 
lvls<-levels(bt) 

t1<-as.data.frame(table(sample(b,5))) 
t2<-as.data.frame(table(sample(b,1))) 
t3<-as.data.frame(table(sample(b,1))) 
t4<-as.data.frame(table(sample(b,8))) 
t5<-as.data.frame(table(sample(b2,20))) 
t6<-as.data.frame(table(sample(b3,18))) 

t1<-cbind(t1,p="A") 
t2<-cbind(t2,p="B") 
t3<-cbind(t3,p="C") 
t4<-cbind(t4,p="D") 
t5<-cbind(t5,p="E") 
t6<-cbind(t6,p="F") 

d<-data.frame() 
d<-rbind(d,t2,t3,t6,t4,t5,t1) 

#.. out of order bins 
ggplot(d,aes(x=factor(Var1),fill=factor(p))) + 
    geom_bar(aes(weight=Freq)) + 
    facet_grid(p ~ ., margins=T)+ 
    ggtitle("out of order bins") 

changeFactor<-function(t,lvls){ 
    temp<-as.numeric(as.character(t)) 
    factor(temp,levels=lvls) 
} 

t1$Var1<-changeFactor(t1$Var1,lvls) 
t2$Var1<-changeFactor(t2$Var1,lvls) 
t3$Var1<-changeFactor(t3$Var1,lvls) 
t4$Var1<-changeFactor(t4$Var1,lvls) 
t5$Var1<-changeFactor(t5$Var1,lvls) 
t6$Var1<-changeFactor(t6$Var1,lvls) 

d<-data.frame() 
d<-rbind(d,t2,t3,t6,t4,t5,t1) 

#.. in order bins 
ggplot(d,aes(x=factor(Var1),fill=factor(p))) + 
    geom_bar(aes(weight=Freq)) + 
    facet_grid(p ~ ., margins=T)+ 
    ggtitle("in order bins") 

ответ

2

короткий ответ: сохранить ваши данные в списках и узнать *pply семейство

set.seed(1234) 
b<-round(runif(100,1,10),digits=2) 
set.seed(2345) 
b2<-round(runif(100,11,20),digits=2) 
set.seed(3456) 
b3<-round(runif(50,15,18),digits=2) 

#.. all potential levels 
bt<-factor(sort(c(b,b2,b3))) 
lvls<-levels(bt) 

options(stringsAsFactors = FALSE) 
f <- function(x, y, z) 
    cbind(data.frame(table(sample(x, y))), p = z) 

datl <- Map(f, list(b,b,b,b,b2,b3), c(5,1,1,8,20,18), LETTERS[1:6]) 

changeFactor<-function(t,lvls){ 
    temp<-as.numeric(as.character(t)) 
    factor(temp,levels=lvls) 
} 

datl <- lapply(rapply(datl, f = function(x) changeFactor(x, lvls), 
        classes = 'factor', how = 'replace'), 
       data.frame) 

d <- do.call(rbind, datl[c(2, 3, 6, 4, 5, 1)]) 

#.. in order bins 
ggplot(d,aes(x=factor(Var1),fill=factor(p))) + 
    geom_bar(aes(weight=Freq)) + 
    facet_grid(p ~ ., margins=T)+ 
    ggtitle("in order bins") 

enter image description here

длинный ответ:

set.seed(1234) 
b<-round(runif(100,1,10),digits=2) 
set.seed(2345) 
b2<-round(runif(100,11,20),digits=2) 
set.seed(3456) 
b3<-round(runif(50,15,18),digits=2) 

#.. all potential levels 
bt<-factor(sort(c(b,b2,b3))) 
lvls<-levels(bt) 

первых, я не хочу никаких неожиданных факторов popping, поэтому stringsAsFactors = FALSE затем напишите функцию, f, чтобы сделать то, что вы хотите, и убедитесь, что она работает

options(stringsAsFactors = FALSE) 
f <- function(x, y, z) 
    cbind(data.frame(table(sample(x, y))), p = z) 

f(b, 5, 'A') 

# Var1 Freq p 
# 1 1.13 1 A 
# 2 1.46 1 A 
# 3 2.09 1 A 
# 4 2.5 1 A 
# 5 7.02 1 A 

, кажется, работает, так что просто Map это списки аргументов и проверить вывод

datl <- Map(f, list(b,b,b,b,b2,b3), c(5,1,1,8,20,18), LETTERS[1:6]) 

# List of 6 
# $ :'data.frame': 5 obs. of 3 variables: 
# ..$ Var1: Factor w/ 5 levels "2.02","3.09",..: 1 2 3 4 5 
# ..$ Freq: int [1:5] 1 1 1 1 1 
# ..$ p : chr [1:5] "A" "A" "A" "A" ... 
# $ :'data.frame': 1 obs. of 3 variables: 
# ..$ Var1: Factor w/ 1 level "1.63": 1 
# ..$ Freq: int 1 
# ..$ p : chr "B" 

так объединить все, чтобы использовать с ggplot

d <- do.call(rbind, datl[c(2, 3, 6, 4, 5, 1)]) 

library(ggplot2) 
#.. out of order bins 
ggplot(d,aes(x=factor(Var1),fill=factor(p))) + 
    geom_bar(aes(weight=Freq)) + 
    facet_grid(p ~ ., margins=T)+ 
    ggtitle("out of order bins") 

enter image description here

changeFactor<-function(t,lvls){ 
    temp<-as.numeric(as.character(t)) 
    factor(temp,levels=lvls) 
} 

снова убедившись, что функция делает то, что он должен делать на кадре один данных

changeFactor(datl[[1]]$Var1, lvls) 

# [1] 2.02 3.09 3.79 3.89 8.3 
# 234 Levels: 1.09 1.12 1.13 1.24 1.36 1.38 1.41 1.46 1.63 1.66 1.81 1.95 ... 19.86 

поэтому применять его снова, чтобы их все сразу и проверить выход

datl <- lapply(rapply(datl, f = function(x) changeFactor(x, lvls), 
        classes = 'factor', how = 'replace'), 
       data.frame) 
str(datl) 
# List of 6 
# $ :'data.frame': 5 obs. of 3 variables: 
# ..$ Var1: Factor w/ 234 levels "1.09","1.12",..: 13 28 41 45 81 
# ..$ Freq: int [1:5] 1 1 1 1 1 
# ..$ p : chr [1:5] "A" "A" "A" "A" ... 
# $ :'data.frame': 1 obs. of 3 variables: 
# ..$ Var1: Factor w/ 234 levels "1.09","1.12",..: 9 
# ..$ Freq: int 1 
# ..$ p : chr "B" 
# ... 

объединить снова и сюжет

d <- do.call(rbind, datl[c(2, 3, 6, 4, 5, 1)]) 

#.. in order bins 
ggplot(d,aes(x=factor(Var1),fill=factor(p))) + 
    geom_bar(aes(weight=Freq)) + 
    facet_grid(p ~ ., margins=T)+ 
    ggtitle("in order bins") 

enter image description here

+0

Благодарим вас. Вы используете некоторые функции, с которыми я не знаком. – bob123

+0

Вы используете некоторые функции, с которыми я не знаком. Я понял, что после публикации я мог бы использовать следующее: d2 $ Var1 <-unlist (tapply (d $ Var1, d $ p, function (dd) changeFactor (dd, lvls))) вместо некоторого кода. Мой пример должен был быть простым примером, поскольку моя настоящая проблема связана с чрезвычайно большими наборами данных. Ваш комментарий относительно «stringsAsFactors» очень важен в этом случае. – bob123

+0

@ bob123: Если ваши большие наборы данных содержат действительно большие векторы факторов, имейте в виду, что опция 'stringsAsFactor = FALSE' заставит вас манипулировать очень большими векторами * строк *, которые намного тяжелее самих факторов (хранятся как простые целые числа в памяти), особенно если ваши уровни имеют длинные имена. Если бы это было так, вам лучше было бы строить свои векторы как факторы с правильными уровнями, а затем использовать их в качестве факторов. –

2

Я думаю, что ваш способ «читать» факторы с as.character это лучший способ, когда вы не знаете, все их «истинные» уровни.

Но так как вы делать знают их (все они хранятся внутри lvls), почему не использовать их непосредственно, когда вы строите ваши ti$Var1 векторов? То есть, вместо того, чтобы:

ti = as.data.frame(table(sample(b,5)));     # automately creates a factor vector ti$Var1 with what is found inside the sample as levels 
ti$Var1 = factor(as.character(ti$Var1), levels = lvls); # replaces it with a new factor, created by reading each value of the previous one and assigning it a level from lvls 

(который, в конечном счете то, что вы делаете), сделать непосредственно:

tab = table(sample(b,5));       
ti = data.frame(myVar = factor(names(tab), lvls)  # creates directly the right factor vector with levels drawn from lvls 
       , myFreq = as.numeric(tab) 
      ); 

(который, в конечном счете то, что вы хотите) (и «даже позволяет вам лучше контролировать на имена столбцов ti «s)

Или в другом месте, но вы тогда получите пустые строки:

factoredSample = factor(sample(b,5), lvls);    # directly associates each drawn value with a level from lvls 
ti = as.data.frame(table(factoredSample));    # and table will then also count the non-represented levels within factoredSample 

(Кстати, я не знаю, было ли это предназначено только для целей запроса, но если вам действительно нужно обрабатывать столько почти идентичных данных. Кадры в вашем скрипте, вы вероятно, используя неправильную структуру данных.)

+0

Благодарим вас за помощь и подробные мысли. Очень полезно! – bob123

+0

@ bob123: Добро пожаловать. Если эти сообщения предоставили все, что вам было нужно, вы можете теперь рассмотреть один ответ как * принятый *, чтобы ваш вопрос был удален со стека;) –

Смежные вопросы