Excel2000 VBAで試みているのですが、
最頻値を求める方法を教えて下さい。
現在、MODEという関数を使ってますが、項目が30個までしか求められません。
60個分の値に対して最頻値を求めることを考えています。ので、
現在は10個毎に区切って求めていますが。。。
また、セルからの読込みになってしまうので、内部の配列変数から最頻値を求めるようにもしてみたいです。
何かごちゃごちゃと書いてしまいましたが、
簡単に質問させていただきますと、最頻値を求める方法を教えて下さい。
よろしくお願いします。
ExcelVBAの最頻値はいわゆる純粋最頻値なので、テストの得点や身長体重などの数値データの集計には不向きです。
まぁ、そんなことはわかってますよね?
ということでExcelのMode関数の個数制限を無くして、内部の配列変数から最頻値を求める関数がなぜか手元にあったのでそのままコピペッ
' 最頻値を求める
Public Function ModeValue(ByVal Values As Variant) As Double
Dim i As Long
Dim LB As Long
Dim UB As Long
Dim mCount As Long
Dim mMaxCount As Long
Call SortValue(Values)
LB = LBound(Values)
UB = UBound(Values)
mCount = 1
mMaxCount = 0
ModeValue = Values(LB)
For i = LB To UB - 1
If Values(i) = Values(i + 1) Then
mCount = mCount + 1
Else
If mCount > mMaxCount Then
mMaxCount = mCount
ModeValue = Values(i)
End If
mCount = 1
End If
Next
If mCount > mMaxCount Then
ModeValue = Values(UB)
End If
End Function
' 配列をソート
Private Function SortValue(ByRef Values As Variant, Optional ByVal ForDirection As Boolean = True) As Long
Dim i As Long
Dim j As Long
Dim LB As Long
Dim UB As Long
Dim mFlag as Long
Dim mTemp As Variant
LB = LBound(Values)
UB = UBound(Values)
IF UB - LB <= 1 Then
SortValue = 0
Exit Function
End IF
For i = LB To UB - 1
For j = LB To LB + UB - i - 1
mFlag = 0
IF ForDirection Then
IF Values(j) > Values(j + 1) Then mFlag = 1
Else
IF Values(j + 1) > Values(j) Then mFlag = 1
End IF
IF mFlag = 1 Then
mTemp = Values(j)
Values(j) = Values(j + 1)
Values(j + 1) = mTemp
End If
Next
Next
SortValue = 1
End Function
とはいえこれはあまり使い道は無いと思いますけど。
例えば30人分のテストの得点をこの関数に放りこんであげても、意味の有るデータは帰ってきません。
重複データが無い場合はExcelならN/Aを返すところですが、この関数は最大データを返します。
ぶっちゃけ使い物になりません。
数値データを集計する場合は間隔尺度や比例尺度を用いて度数分布表を作成し、そこから最頻値を求めることになります。
この場合階級には幅が存在するようになるため、最頻値は最大階級の中心値というわけにはいきません。
まぁ、これ以上は質問内容とずれてくるのでひとまず逃亡。
>現在、MODEという関数を使ってますが、項目が30個までしか求められません。
>60個分の値に対して最頻値を求めることを考えています。ので、
>現在は10個毎に区切って求めていますが。。。
>また、セルからの読込みになってしまうので、内部の配列変数から最頻値を求めるようにもしてみたいです。
値をダミーのシートにコピーしてセル範囲を指定するのはどうでしょうか?
配列から求める場合は引数に配列を指定すればいけます。
Private Sub test()
Dim work(50) As Integer
Dim i As Integer
For i = 0 To 50
work(i) = Rnd * 10
Next
MsgBox WorksheetFunction.Mode(work)
End Sub
ツイート | ![]() |