web-dev-qa-db-ja.com

モードを見つけるための組み込み関数はありますか?

Rでは、mean()median()はあなたが期待することをする標準的な関数です。 mode()は、オブジェクトの内部記憶モードを表します。引数の中で最も頻繁に現れる値ではありません。しかし、ベクトル(またはリスト)の統計モードを実装する標準ライブラリ関数はありますか?

350
Nick

もう1つの解決策、これは数値と文字/因子データの両方に機能します。

Mode <- function(x) {
  ux <- unique(x)
  ux[which.max(tabulate(match(x, ux)))]
}

私の変わった小さなマシンでは、それは約0.5秒で10M整数ベクトルのモードを生成して見つけることができます。

データセットに複数のモードがある場合、上記の解法はwhich.maxと同じアプローチを取り、モードセットの最初に現れる値を返します。 すべてのモードを返すには、この変種を使用します(コメントの@digEmAllから)。

Modes <- function(x) {
  ux <- unique(x)
  tab <- tabulate(match(x, ux))
  ux[tab == max(tab)]
}
359
Ken Williams

単変量単峰性(場合によっては多峰性)データのモードの推定量と通常の確率分布のモードの値を提供するパッケージmodeestがあります。

mySamples <- c(19, 4, 5, 7, 29, 19, 29, 13, 25, 19)

library(modeest)
mlv(mySamples, method = "mfv")

Mode (most likely value): 19 
Bickel's modal skewness: -0.1 
Call: mlv.default(x = mySamples, method = "mfv")

詳しくは、このページを参照してください

62
George Dontas

rメーリングリストでこれを見つけました。役に立つことを願っています。それは私がとにかく考えていたものでもあります。データをtable()し、ソートしてから名前を選択します。ハックだけどうまくいくはずだ。

names(sort(-table(x)))[1]
54
Dan

上記のKen Williams氏の投稿が素晴らしいことがわかりました。NA値を説明するために数行を追加し、それを簡単にするための関数にしました。

Mode <- function(x, na.rm = FALSE) {
  if(na.rm){
    x = x[!is.na(x)]
  }

  ux <- unique(x)
  return(ux[which.max(tabulate(match(x, ux)))])
}
42
jprockbelly

連続的な一変量分布(例えば正規分布)から来ると信じる数のベクトルの最頻値を推定するための迅速で汚い方法は、以下の関数を定義して使うことです:

estimate_mode <- function(x) {
  d <- density(x)
  d$x[which.max(d$y)]
}

それからモード推定値を得るために:

x <- c(5.8, 5.6, 6.2, 4.1, 4.9, 2.4, 3.9, 1.8, 5.7, 3.2)
estimate_mode(x)
## 5.439788
28
Rasmus Bååth

次の関数は3つの形式で提供されています。

method = "mode" [default]:単峰性ベクトルのモードを計算し、そうでなければNAを返します
method = "nmodes":ベクトル内のモード数を計算します
method = "modes":単峰性または多峰性ベクトルのすべてのモードをリストします

modeav <- function (x, method = "mode", na.rm = FALSE)
{
  x <- unlist(x)
  if (na.rm)
    x <- x[!is.na(x)]
  u <- unique(x)
  n <- length(u)
  #get frequencies of each of the unique values in the vector
  frequencies <- rep(0, n)
  for (i in seq_len(n)) {
    if (is.na(u[i])) {
      frequencies[i] <- sum(is.na(x))
    }
    else {
      frequencies[i] <- sum(x == u[i], na.rm = TRUE)
    }
  }
  #mode if a unimodal vector, else NA
  if (method == "mode" | is.na(method) | method == "")
  {return(ifelse(length(frequencies[frequencies==max(frequencies)])>1,NA,u[which.max(frequencies)]))}
  #number of modes
  if(method == "nmode" | method == "nmodes")
  {return(length(frequencies[frequencies==max(frequencies)]))}
  #list of all modes
  if (method == "modes" | method == "modevalues")
  {return(u[which(frequencies==max(frequencies), arr.ind = FALSE, useNames = FALSE)])}  
  #error trap the method
  warning("Warning: method not recognised.  Valid methods are 'mode' [default], 'nmodes' and 'modes'")
  return()
}
14
Chris

ここで、別の解決策:

freq <- tapply(mySamples,mySamples,length)
#or freq <- table(mySamples)
as.numeric(names(freq)[which.max(freq)])
10
teucer

まだ投票することはできませんが、RasmusBååthの答えが私が探していたものです。しかし、私はそれを少し修正して、例えば0と1の間の値のみの分布にすることができます。

estimate_mode <- function(x,from=min(x), to=max(x)) {
  d <- density(x, from=from, to=to)
  d$x[which.max(d$y)]
}

あなたは、あなたのディストリビューションをまったく制限したくない場合は、= - "BIG NUMBER"から= "BIG NUMBER"に設定したいと思うかもしれません。

9
AleRuete

Ken Williamsの答えを少し修正したもので、オプションのna.rmreturn_multipleを追加しました。

names()に依存する回答とは異なり、この回答は戻り値にxのデータ型を維持します。

stat_mode <- function(x, return_multiple = TRUE, na.rm = FALSE) {
  if(na.rm){
    x <- na.omit(x)
  }
  ux <- unique(x)
  freq <- tabulate(match(x, ux))
  mode_loc <- if(return_multiple) which(freq==max(freq)) else which.max(freq)
  return(ux[mode_loc])
}

これを表示するには、オプションのパラメータと連携してデータ型を管理します。

foo <- c(2L, 2L, 3L, 4L, 4L, 5L, NA, NA)
bar <- c('mouse','mouse','dog','cat','cat','bird',NA,NA)

str(stat_mode(foo)) # int [1:3] 2 4 NA
str(stat_mode(bar)) # chr [1:3] "mouse" "cat" NA
str(stat_mode(bar, na.rm=T)) # chr [1:2] "mouse" "cat"
str(stat_mode(bar, return_mult=F, na.rm=T)) # chr "mouse"

簡略化してくれた@Frankに感謝します。

8
C8H10N4O2

モードを生成するために以下のコードを書きました。

MODE <- function(dataframe){
    DF <- as.data.frame(dataframe)

    MODE2 <- function(x){      
        if (is.numeric(x) == FALSE){
            df <- as.data.frame(table(x))  
            df <- df[order(df$Freq), ]         
            m <- max(df$Freq)        
            MODE1 <- as.vector(as.character(subset(df, Freq == m)[, 1]))

            if (sum(df$Freq)/length(df$Freq)==1){
                warning("No Mode: Frequency of all values is 1", call. = FALSE)
            }else{
                return(MODE1)
            }

        }else{ 
            df <- as.data.frame(table(x))  
            df <- df[order(df$Freq), ]         
            m <- max(df$Freq)        
            MODE1 <- as.vector(as.numeric(as.character(subset(df, Freq == m)[, 1])))

            if (sum(df$Freq)/length(df$Freq)==1){
                warning("No Mode: Frequency of all values is 1", call. = FALSE)
            }else{
                return(MODE1)
            }
        }
    }

    return(as.vector(lapply(DF, MODE2)))
}

試してみよう:

MODE(mtcars)
MODE(CO2)
MODE(ToothGrowth)
MODE(InsectSprays)
7
Tyler Rinker

このハックはうまくいくはずです。モードの数と同様にあなたに値を与えます:

Mode <- function(x){
a = table(x) # x is a vector
return(a[which.max(a)])
}
6
Nsquare

モードまたは関連するメトリックを計算する@ Chrisの機能に基づいていますが、頻度の計算にはKen Williamsの方法を使用しています。これはモードがまったくない場合(すべての要素が同じ頻度である場合)の修正と、より読みやすいmethod名を提供します。

Mode <- function(x, method = "one", na.rm = FALSE) {
  x <- unlist(x)
  if (na.rm) {
    x <- x[!is.na(x)]
  }

  # Get unique values
  ux <- unique(x)
  n <- length(ux)

  # Get frequencies of all unique values
  frequencies <- tabulate(match(x, ux))
  modes <- frequencies == max(frequencies)

  # Determine number of modes
  nmodes <- sum(modes)
  nmodes <- ifelse(nmodes==n, 0L, nmodes)

  if (method %in% c("one", "mode", "") | is.na(method)) {
    # Return NA if not exactly one mode, else return the mode
    if (nmodes != 1) {
      return(NA)
    } else {
      return(ux[which(modes)])
    }
  } else if (method %in% c("n", "nmodes")) {
    # Return the number of modes
    return(nmodes)
  } else if (method %in% c("all", "modes")) {
    # Return NA if no modes exist, else return all modes
    if (nmodes > 0) {
      return(ux[which(modes)])
    } else {
      return(NA)
    }
  }
  warning("Warning: method not recognised.  Valid methods are 'one'/'mode' [default], 'n'/'nmodes' and 'all'/'modes'")
}

Kenの方法を使用して周波数が計算されるので、パフォーマンスも最適化されます。AkselAの投稿を使用して、私の関数がKenのパフォーマンスにどの程度近いかを示します Comparison of Mode functions

5
hugovdberg

これはかなりうまくいきます

> a<-c(1,1,2,2,3,3,4,4,5)
> names(table(a))[table(a)==max(table(a))]
3
statistic1979

Rは非常に多くのアドオンパッケージを持っているので、それらのいくつかは[リスト] /シリーズ/ベクトルの[統計的]モードを提供するかもしれません。

しかし、R自身の標準ライブラリには、そのような組み込みメソッドはありません。これを回避する1つの方法は、次のような構成要素を使用することです(そして頻繁に使用するのであればこれを関数に変えることもできます)。

mySamples <- c(19, 4, 5, 7, 29, 19, 29, 13, 25, 19)
tabSmpl<-tabulate(mySamples)
SmplMode<-which(tabSmpl== max(tabSmpl))
if(sum(tabSmpl == max(tabSmpl))>1) SmplMode<-NA
> SmplMode
[1] 19

より大きなサンプルリストでは、max(tabSmpl)の値に一時的な変数を使うことを考えるべきです(私はRがこれを自動的に最適化することを知らない)

参照:「中央値とモードはどうですか?」を参照してください。この中で KickStarting Rレッスン
これは(少なくともこのレッスンの執筆時点で)Rにモード関数がないことを確認しているようです(よくわかったように... mode()は変数の型をアサートするために使用されます).

3
mjv

これはモードを見つける関数です。

mode <- function(x) {
  unique_val <- unique(x)
  counts <- vector()
  for (i in 1:length(unique_val)) {
    counts[i] <- length(which(x==unique_val[i]))
  }
  position <- c(which(counts==max(counts)))
  if (mean(counts)==max(counts)) 
    mode_x <- 'Mode does not exist'
  else 
    mode_x <- unique_val[position]
  return(mode_x)
}

モードはあらゆる状況で役立つわけではありません。そのため、関数はこの状況に対処する必要があります。次の機能を試してください。

Mode <- function(v) {
  # checking unique numbers in the input
  uniqv <- unique(v)
  # frquency of most occured value in the input data
  m1 <- max(tabulate(match(v, uniqv)))
  n <- length(tabulate(match(v, uniqv)))
  # if all elements are same
  same_val_check <- all(diff(v) == 0)
  if(same_val_check == F){
    # frquency of second most occured value in the input data
    m2 <- sort(tabulate(match(v, uniqv)),partial=n-1)[n-1]
    if (m1 != m2) {
      # Returning the most repeated value
      mode <- uniqv[which.max(tabulate(match(v, uniqv)))]
    } else{
      mode <- "Two or more values have same frequency. So mode can't be calculated."
    }
  } else {
    # if all elements are same
    mode <- unique(v)
  }
  return(mode)
}

出力、

x1 <- c(1,2,3,3,3,4,5)
Mode(x1)
# [1] 3

x2 <- c(1,2,3,4,5)
Mode(x2)
# [1] "Two or more varibles have same frequency. So mode can't be calculated."

x3 <- c(1,1,2,3,3,4,5)
Mode(x3)
# [1] "Two or more values have same frequency. So mode can't be calculated."
2
Jibin

以下はRのベクトル変数のモードを見つけるために使うことができるコードです。

a <- table([vector])

names(a[a==max(a)])
2
GauravS

私はこれらすべてのオプションを調べていて、それらの相対的な機能とパフォーマンスについて疑問に思い始めたので、いくつかのテストを行いました。他の誰かが同じことに興味を持っている場合に備えて、私はここで私の結果を共有しています。

ここに掲載されているすべての関数に煩わされたくないので、いくつかの基準に基づいてサンプルに焦点を当てることにしました。関数は文字、因子、論理および数値ベクトルの両方で機能します。そして出力は「賢明」であるべきです。

私は自分自身の関数も追加しました。それはクリスピーのものと同じrleの考えに基づいていますが、より一般的な用途に適応されています。

library(magrittr)

Aksel <- function(x, freq=FALSE) {
    z <- 2
    if (freq) z <- 1:2
    run <- x %>% as.vector %>% sort %>% rle %>% unclass %>% data.frame
    colnames(run) <- c("freq", "value")
    run[which(run$freq==max(run$freq)), z] %>% as.vector   
}

set.seed(2)

F <- sample(c("yes", "no", "maybe", NA), 10, replace=TRUE) %>% factor
Aksel(F)

# [1] maybe yes  

C <- sample(c("Steve", "Jane", "Jonas", "Petra"), 20, replace=TRUE)
Aksel(C, freq=TRUE)

# freq value
#    7 Steve

microbenchmarkを介して、2つのテストデータセットに対して5つの関数を実行しました。関数名はそれぞれの作者を指します。

enter image description here

Chrisの関数はデフォルトでmethod="modes"およびna.rm=TRUEに設定されていますが、それ以外の点ではこれらの関数が著者のここで紹介したように使用されています。

速度だけの問題ではKensバージョンが手ごろに勝ちますが、実際にどれだけ多くても、1つのモードだけを報告するのはこれらのうちの唯一のものです。よくあることですが、スピードと汎用性の間にはトレードオフがあります。 method="mode"では、Chrisのバージョンは1つのモードがあれば値を返し、そうでなければNAを返します。いい感じだと思います。私はまた、いくつかの関数が増加した数のユニークな値によってどのように影響されるか、他のものはほとんど同じではないというのも面白いと思います。原因として論理/数値を排除する以外に、その理由を理解するためにコードを詳細には調べていません。

2
AkselA

これには複数の解決策があります。私は最初のものをチェックし、その後私自身のものを書きました。誰かに役立つ場合はここに投稿してください。

Mode <- function(x){
  y <- data.frame(table(x))
  y[y$Freq == max(y$Freq),1]
}

いくつかの例を使ってテストしましょう。私はirisデータセットを取っています。数値データでテストできます

> Mode(iris$Sepal.Length)
[1] 5

確認できるものは正しいです。

これで、アイリスデータセット(Species)の唯一の数値以外のフィールドにモードがなくなりました。私たち自身の例でテストしましょう

> test <- c("red","red","green","blue","red")
> Mode(test)
[1] red

編集

コメントで述べたように、ユーザーは入力タイプを保存したいと思うかもしれません。その場合、モード関数は次のように修正できます。

Mode <- function(x){
  y <- data.frame(table(x))
  z <- y[y$Freq == max(y$Freq),1]
  as(as.character(z),class(x))
}

関数の最後の行は、単純に最終モード値を元の入力の型に強制します。

2
Abhiroop Sarkar

Ken Williamsの単純な関数が好きですが、複数のモードが存在する場合はそれらを取得したいと思います。それを念頭に置いて、私は次の関数を使用します。これはモードが複数か単一の場合にモードのリストを返します。

rmode <- function(x) {
  x <- sort(x)  
  u <- unique(x)
  y <- lapply(u, function(y) length(x[x==y]))
  u[which( unlist(y) == max(unlist(y)) )]
} 
2
RandallShanePhD

別の可能な解決策:

Mode <- function(x) {
    if (is.numeric(x)) {
        x_table <- table(x)
        return(as.numeric(names(x_table)[which.max(x_table)]))
    }
}

使用法:

set.seed(100)
v <- sample(x = 1:100, size = 1000000, replace = TRUE)
system.time(Mode(v))

出力:

   user  system elapsed 
   0.32    0.00    0.31 
1
Naimish Agarwal

すべての値を頻度順に並べるもう1つの簡単な方法はrleを使うことです。

df = as.data.frame(unclass(rle(sort(mySamples))))
df = df[order(-df$lengths),]
head(df)
1
Alice Purcell

(おそらく連続的な)分布の平滑化された最大値を識別するために、density()関数を使用します。

function(x) density(x, 2)$x[density(x, 2)$y == max(density(x, 2)$y)]

ここで、xはデータコレクションです。平滑化を調整する密度関数のadjustパラメータに注意してください。

1
Yo B.

あなたの観測は classes from 実数 であり、モードであることを期待します。観測値が2、2、3、および3の場合はが2.5になるので、mode = l1 + i * (f1-f0) / (2f1 - f0 - f2)を使用してモードを推定できます。ここで、l1............................. f1..最も頻度の高いクラスの頻度、f0..最も頻度の高いクラスの前のクラスの頻度、 f2 ..最も頻度の高いクラスの後のクラスの頻度とi..与えられたクラス間隔in 123

#Small Example
x <- c(2,2,3,3) #Observations
i <- 1          #Class interval

z <- hist(x, breaks = seq(min(x)-1.5*i, max(x)+1.5*i, i), plot=F) #Calculate frequency of classes
mf <- which.max(z$counts)   #index of most frequent class
zc <- z$counts
z$breaks[mf] + i * (zc[mf] - zc[mf-1]) / (2*zc[mf] - zc[mf-1] - zc[mf+1])  #gives you the mode of 2.5


#Larger Example
set.seed(0)
i <- 5          #Class interval
x <- round(rnorm(100,mean=100,sd=10)/i)*i #Observations

z <- hist(x, breaks = seq(min(x)-1.5*i, max(x)+1.5*i, i), plot=F)
mf <- which.max(z$counts)
zc <- z$counts
z$breaks[mf] + i * (zc[mf] - zc[mf-1]) / (2*zc[mf] - zc[mf-1] - zc[mf+1])  #gives you the mode of 99.5

最も頻度の高いレベル が必要で、最も頻度の高いレベルがある場合は、すべてを取得できます。それらのうちと:

x <- c(2,2,3,5,5)
names(which(max(table(x))==table(x)))
#"2" "5"
1
user10488504

これは、非常に短いベクトルを高速化することによって、jprockbellyの答えに基づいています。これは、data.frameまたはたくさんの小さなグループを持つdatatableにモードを適用するときに便利です。

Mode <- function(x) {
   if ( length(x) <= 2 ) return(x[1])
   if ( anyNA(x) ) x = x[!is.na(x)]
   ux <- unique(x)
   ux[which.max(tabulate(match(x, ux)))]
}
1
Dan Houghton

次の機能を試すことができます。

  1. 数値を因子に変換する
  2. 度数表を得るためにsummary()を使う
  3. 戻りモード頻度が最も大きいインデックス
  4. 複数のモードがある場合でも、係数を数値に変換し直すと、この関数はうまく機能します。
mode <- function(x){
  y <- as.factor(x)
  freq <- summary(y)
  mode <- names(freq)[freq[names(freq)] == max(freq)]
  as.numeric(mode)
}
0
Wei

計算モードは主に因子変数の場合で、それから我々は使用することができます

labels(table(HouseVotes84$V1)[as.numeric(labels(max(table(HouseVotes84$V1))))])

HouseVotes84は 'mlbench'パッケージで利用可能なデータセットです。

それは最大ラベル値を与えるでしょう。関数を記述しなくても、組み込み関数自体で使用する方が簡単です。

0