Stata 11では、関数rowmedianにより、egenで直接行中央値を計算できます。
どのように行中央値を計算するのですか?
タイトル | Calculating row medians | |
著者 | Nicholas J. Cox, Durham University |
統計ソフトで中央値を計算することは簡単になるはずですし、通常はそうなっていると思います。
この問題は、実際に発生するからというだけでなく、議論する価値があります。
基本をおさらいすると、ある変数の中央値が欲しい場合、その変数でソートし、中央値を自分で取り出すことができます。 オブザベーションの一部のみに興味があったり、欠損値がある場合は、いくつかの注意が必要です。 ほとんどの場合、ユーザーはsummarize, detailを起動し、そのような事柄をすべて処理し、結果の中から中央値を特定します。 これはr(p50)としてすぐにメモリに残ります。
もし代わりに中央値を変数に入れたいなら、egen, median()を使うことができます。 これはデータがグループに分かれていて、各グループの中央値を記録しておき、後で利用する場合に最も理にかなっています。 したがって、egen, median()とby:を併用することになります。
同じ種類の変数がたくさんあるとき、簡単に答えが見つかることがあります。 もしそれらの変数が本当にパネルや縦断的なデータであれば、longを再形成して別のデータ構造で作業すべきです。 そうすれば、行の中央値だけでなく、パネルの中央値も、そのようなデータで行いたいほとんどすべての種類の分析も、ずっと簡単になるでしょう。
もし行変数の値が数値順で、例えばy1は常にy2以下であり、y2はy3以下というように分かっていれば、中央値は変数の数が奇数か偶数かによって、変数の1つまたは変数の2つの平均として直接計算することができます。
次に、行の中央値を取りたい変数が少ない場合(2、3、または4)、これも値が欠損していない場合です。 2変数の中央値は平均値と同じなので、最初のケースは簡単です:
. gen median = (y1 + y2) / 2
3変数のあまり知られていないトリックは、問題を簡単に解決します:
. gen median = y1 + y2 + y3 - min(y1, y2, y3) - max(y1, y2, y3)
つまり:行合計を計算し、最小値と最大値を差し引きます。 残ったものが中央値です。
これで4変数のトリックがすぐにできます。
. gen median = (y1 + y2 + y3 + y4 - /// min(y1, y2, y3, y4) - max(y1, y2, y3, y4)) / 2
つまり、行の合計を計算し、最小値と最大値を引きます。 残ったのは内側の2つの値の合計で、半分にすると中央値になります。
5つ以上の変数に対する簡単なトリックは、一般的には証拠がありません。 より厄介な仮定は、値が欠落していないことです。 欠損値による問題を解決するためのいくつかの余地がある。
. egen nmissing = rowmiss(varlist)
から欠損数を計算することができますが、いくつかの変数については、その場で欠損変数を数えることは同じくらい簡単です。
任意の欠損変数で、2の中央値は
. gen median = (y1 + y2) / 2 . replace median = max(y1, y2) if median == .
によって救い出すことができます。このコマンド列では、値のいずれかが欠損していればmax(y1、 y2) は nonmissing という事実を使っています。 もし両方の値が欠損していても、欠損は欠損で上書きされるだけなので、実際には損をすることはありません。 min(y1, y2) と書いてもかまいませんが、その方が楽でしょう。 (なぜ結果が同じになるのか?)
同様に、3の中央値も救済されることがある。
. gen median = y1 + y2 + y3 - min(y1, y2, y3) - max(y1, y2, y3)
y1、y2、y3がすべて欠損している場合、すでに欠損という唯一の可能な答えが出ています。
. replace median = max(y1, y2, y3) if (missing(y1) + missing(y2) + missing(y3)) == 2
2つの変数が欠損している場合、max()からもう1つの変数を得ることができ、それは自動的に中央値になります。 代わりに0を使うことで、欠測が無視されることを確認します。 もしすべての変数が正(またはゼロ)であることが分かっていれば、cond(missing(y1), 0, y1) のような項ではなく、max(y1, 0) を使うことができ、もしすべての変数が負(またはゼロ)でなければならないと分かっていれば、代わりに min(y1, 0) が使えるでしょう。 さらに、egenでも同じことができます。
. egen rowsum = rowsum(y1 y2 y3). replace median = rowsum / 2 ///if (missing(y1) + missing(y2) + missing(y3)) == 1
明らかに、ここまでのコードは行中央値を得るために必ずしもソートする必要がないことを示すという好奇心の価値がありますが、より系統だったアプローチを体現するプログラムが本当に必要なのです。 コミュニティから提供された関数を探し、それらを注意深く見ると、その理由が見えてきます。 要するに、Stata 9.以前は2つのアプローチが可能でした
1つは、STB-57(Stata 5必須)のrmed()というegenに実装されているもので、観測値をループし、値を変数にコピーして中央値を取得するものです。 残念ながら、このアプローチは、関係する変数の数がオブザベーションの数より大きくないことを仮定しています。 これは通常ですが、必ずしもそうではありません。 8604>
2つ目は、egenで実装されているSSCのrmedf()(Stata 6が必要)で、データセットをその場で再構築し、中央値を計算し、再び再構築する方法である。 データセットの再構築はegen関数の途中で行うべきものではないことは議論の余地がありますが、いずれにせよこの方法は十分なメモリが利用できない場合、簡単に失敗します。
しかしながらStata 9では、Mataを使用するというもっと前向きな機会がやってきました。 SSCのegenmoreパッケージにはegen, rowmedian()が含まれています。 これは以前のegen関数よりはるかに高速で、基本的なループはまだ観測値に対するループであるにもかかわらず、余分なメモリをほとんど必要としません。 以下はそのコードです:
program _growmedian version 9 gettoken type 0 : 0 gettoken h 0 : 0 gettoken eqs 0 : 0 syntax varlist(numeric) if `"`by'"' != "" { _egennoby rowmedian() `"`by'"' /* NOTREACHED */ } marksample touse, novarlist quietly { mata : row_median("`varlist'", "`touse'", "`h'", "`type'") } end mata : void row_median(string scalar varnames, string scalar tousename, string scalar medianname, string scalar type) { real matrix y real colvector median, row real scalar n st_view(y, ., tokens(varnames), tousename) median = J(rows(y), 1, .) for(i = 1; i