2013-03-02 2 views
4

Я бы хотел рассчитать наиболее часто используемый коэффициент по категориям с помощью plyr, используя код ниже. В кадре данных b показан запрошенный результат. Почему c$mlevels имеет значение «числовое»?Вычисление наиболее частого уровня по категориям с помощью plyr

require(plyr) 
set.seed(0) 
a <- data.frame(cat=round(runif(100, 1, 3)), 
       levels=factor(round(runif(100, 1, 10)))) 
mode <- function(x) names(table(x))[which.max(table(x))] 
b <- data.frame(cat=1:3, 
       mlevels=c(mode(a$levels[a$cat==1]), 
         mode(a$levels[a$cat==2]), 
         mode(a$levels[a$cat==3]))) 
c <- ddply(a, .(cat), summarise, 
      mlevels=mode(levels)) 

ответ

5

При использовании summarise, plyr, кажется, «не видит» функцию, объявленную в глобальной среде перед проверкой функции в base:

Мы можем проверить это, используя удобный pryr пакет Хэдли. Вы можете установить его с помощью следующих команд:

library(devtools) 
install_github("pryr") 


require(pryr) 
require(plyr) 
c <- ddply(a, .(cat), summarise, print(where("mode"))) 
# <environment: namespace:base> 
# <environment: namespace:base> 
# <environment: namespace:base> 

В принципе, это не читает/знаешь/см вашихmode функцию. Есть два варианта. Первое - это то, что предложил @AnandaMahto, и я бы сделал то же самое, и посоветовал бы вам придерживаться этого. Другой альтернативой является не использовать summarise и называть его с помощью function(.), так что функция mode в вашей глобальной среде «виден».

c <- ddply(a, .(cat), function(x) mode(x$levels)) 
# cat V1 
# 1 1 6 
# 2 2 5 
# 3 3 9 

Почему это работает?

c <- ddply(a, .(cat), function(x) print(where("mode"))) 
# <environment: R_GlobalEnv> 
# <environment: R_GlobalEnv> 
# <environment: R_GlobalEnv> 

Потому что, как вы видите выше, он читает вашу функцию, которая сидит в global environment.

> mode # your function 
# function(x) 
#  names(table(x))[which.max(table(x))] 
> environment(mode) # where it sits 
# <environment: R_GlobalEnv> 

в противоположность:

> base::mode # base's mode function 
# function (x) 
# { 
#  some lines of code to compute mode 
# } 
# <bytecode: 0x7fa2f2bff878> 
# <environment: namespace:base> 

Here's an awesome wiki на environments от Hadley, если вы заинтересованы в предоставлении ему чтение/изучение далее.

+1

+1, Это лучший ответ, чем мой. Мне было слишком лениво исследовать, где plyr искал «режим», поэтому я просто переименовал и упростил его. – A5C1D2H2I1M1N2O1R2T1

+0

Спасибо за ответ, сейчас он работает. Я пытаюсь обобщить: режим уже существует в глобальной среде, и поэтому plyr использует эту функцию, предоставленную мной. – naund

+0

@ пользователь2126360, 'режим' в' база'. – A5C1D2H2I1M1N2O1R2T1

2

Вы в значительной степени используются исключительно существующие названия функций в вашем примере: levels, cat и mode. Как правило, это не создает большой проблемы - например, вызов data.frame «df» не нарушает функцию df() R. Но это почти всегда приводит к более двусмысленному или запутанному коду, и в этот случай, он заставил вещи «сломаться». Ответ Аруна делает отличную работу по показу почему.

Вы можете легко исправить свою проблему, переименовав свою функцию «режим». В приведенном ниже примере я немного упростил его в дополнение к переименованию, и он работает так, как вы ожидали.

Mode <- function(x) names(which.max(table(x))) 
ddply(a, .(cat), summarise, 
     mlevels=Mode(levels)) 
# cat mlevels 
# 1 1  6 
# 2 2  5 
# 3 3  9 

Конечно, есть очень громоздкий обходной путь: Используйте get и указать, где искать функции.

> mode <- function(x) names(table(x))[which.max(table(x))] 
> ddply(a, .(cat), summarise, mlevels = get("mode", ".GlobalEnv")(levels)) 
    cat mlevels 
1 1  6 
2 2  5 
3 3  9 
+0

(++ 1) для опрятного трюка с 'get'! – Arun

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