Pandasでログ統計処理スクリプト(その3)
コールサイン文字列から国内エリアと日本以外の局を判別する関数です。あまり厳密な方法ではないです(例えば/MMやゲストオペレータのコールなど)。pythonは正規表現のマッチングがシンプルに書けないし、後方参照が仕方がまどろっこしいので困ったものです。
def call_area(callsign): jacall_re = re.compile('(^J[AD-S]\d)|(^[78][J-N]\d)') area_ja_re = re.compile('^J[AD-S](\d)') area_7_re = re.compile('^7[K-N][1-4]') area_7j_re = re.compile('^7J(\d)') area_8_re = re.compile('^8[J-N](\d)') area_jd1_re = re.compile('^JD1') call_sp = callsign.split('/') if len(call_sp) >= 2: if jacall_re.search(call_sp[0]): m_areanum = re.match('(\d)', call_sp[1]) if m_areanum: area = 'JA' + m_areanum.group(1) else: area = 'DX' else: area = 'DX' else: if jacall_re.search(callsign): m_ja = area_ja_re.search(callsign) m_7 = area_7_re.search(callsign) m_7j = area_7j_re.search(callsign) m_8 = area_8_re.search(callsign) if m_ja: area = 'JA' + m_ja.group(1) elif m_7: area = 'JA1' elif m_7j: area = 'JA' + m_7j.group(1) elif m_8: area = 'JA' + m_8.group(1) else: area = 'DX' m_jd1 = area_jd1_re.search(callsign) if m_jd1: area = 'DX' return area
この関数を使って例えば、
In [12]: call_area('JF1DIR') Out[12]: 'JA1' In [13]: call_area('JF1DIR/9') Out[13]: 'JA9' In [14]: call_area('KH0/JF1DIR') Out[14]: 'DX'
とエリアに対応する文字列を返します。前回の(その2)でこの関数を使って新たに'area'列にエリア文字列の列を作っておきました。
さて、ここからが本番です。
まずはこのログからどのバンドの運用があったのかを調べるのは、
In [15]: set(log.freq) Out[15]: {3.5, 7.0, 14.0, 21.0, 28.0}
とします。log.freqでfreq列のリストが得られ、そのset(重複を除いたリスト)を表示させればよいのです。
次に、ログのすべてのデータから、エリア別の統計を取りたい場合は、
In [16]: log.area.value_counts() Out[16]: DX 419 JA1 29 JA3 12 JA2 11 JA0 9 JA7 7 JA6 6 JA4 4 JA8 2 JA5 1 Name: area, dtype: int64
で得られます。python/pandasの偉いところはIPythonのインタラクティブ表示やスクリプト内のprint()文で表示させるとちゃんと整形されて表示されるということです。ちなみに、このメソッドの返り値はSeries型になっているので、
In [17]: a = log.area.value_counts() In [18]: a[0] Out[18]: 419 In [19]: a.index[0] Out[19]: 'DX'
で個々の値に参照することができます。
例えば7MHzの運用分だけでエリア別統計を取りたい場合は、freq列にフィルターをかけてカウントします。
In [20]: log[log.freq==7].area.value_counts() Out[20]: DX 59 JA1 16 JA2 7 JA3 6 JA0 5 JA7 5 JA4 1 JA6 1 JA5 1 Name: area, dtype: int64
QSO数だけならば、
In [21]: log[log.freq==7].area.count() Out[21]: 101
でよいです。
QSO時間でログを切り取る、例えば、2012年5月26日18時〜24時までのデータだけを切り出す場合は、
In [22]: log[(log.datetime>=datetime(2012,5,26,18,0,0,0))&(log.datetime
のようにします。
call列をキーにログ全体をソートするには、
In [23]: log.sort('call').head() Out[23]: call datetime urrst myrst freq mode urnr mynr area 66 3V8BB 2012-05-26 06:25:00 599 599 21.0 CW 67 503 DX 33 3Z2X 2012-05-26 05:20:00 599 599 21.0 CW 34 68 DX 41 6M0NR 2012-05-26 05:32:00 599 599 21.0 CW 42 172 DX 165 6M0NR 2012-05-26 11:38:00 599 599 7.0 CW 167 192 DX 141 7J1YAJ 2012-05-26 10:55:00 599 599 7.0 CW 143 3039 JA1
ただし元のlogデータフレームには影響しない非破壊のメソッドです。
以上のようなデータフレームに対するメソッドを駆使すればやりたいことは大体出来てしまいます。位置から自分でプログラミングすると結構面倒ですが、上記メソッドをスクリプト内に組み込んであげれば各種統計解析が可能となります。いかがでしょう?pythonの概念がわかってしまうと意外と簡単ですよね。