pikesaku’s blog

個人的な勉強メモです。記載内容について一切の責任は持ちません。

pythonのcymruwhoisモジュールでIPアドレスからwhois情報取得

使い方が簡単

#! /usr/bin/env python3
# -*- coding: utf-8 -*-


from cymruwhois import Client

# 一個だけデータを取得する場合
c = Client()
r = c.lookup('8.8.8.8')
print('ANS:    ' + r.asn)
print('IP :    ' + r.ip)
print('PREFIX: ' + r.prefix)
print('CC:     ' + r.cc)
print('OWNER:  ' + r.owner)

# 複数データを取得する場合

# 悪い例
# 同じCIDR内だが、都度クエリが発生
# 以下URLにも注意書きがあり。loop内で使うと性能悪い
# http://pythonhosted.org/cymruwhois/api.html
for i in range(256):
    ip = '8.8.8.' + str(i + 1)
    r = c.lookup(ip)
    print(r.asn)


# 良い例
# 同じCIDR内なので、通信は最初の一回だけ。
ips = list()
for i in range(254):
    ips.append('8.8.8.' + str(i + 1))

for r in c.lookupmany(ips):
    print(r.asn)


信頼性もありそう

・CentOS7のwgetコマンドは引数に指定されたIPを管理するレジストラを探すためにDNS(逆引き&TXTレコード)を使っている。
 その問い合わせ先がcymruのサーバであった。ここでIPアドレスを管理するレジストラ情報を得て、whoisプロトコルで情報を得ている。
 →CentOSwgetに組み込まれているサービスに関与している組織。

・cymruとは?
 
www.team-cymru.org

 Googleや名だたるITサービスプロバイダーがパートナー

備考

whoisはレスポンスの規則がないとの情報あり。RDAPなるものを知り、これがいいと思ったがCentOS7環境でRDAP対応のipwhoisが上手く動かず、困っていたところで見つけたモジュール。
Macではipwhois正常に動く。。。使いやすメリットでcymruwhoisを使おう。cymruwhoisはRDAP未対応?(デフォルト動作ではwhoisプロトコルを利用)

jubatus anomalyのnum_rules動作検証(jubaanomalyにデータを投入するツール)

説明

jubaanomalyにデータを学習させたり、外れ値を計算させるツール。

指定可能なオプションは以下の通り。

オプション 意味
-t num_rulesのタイプ(num or str or log)を指定。必須指定オプション
-c データ学習前に既存データをクリアする。省略可能。デフォルトは無効
-s 学習データをファイルに保存する。省略可能。デフォルトは無効
-d 学習済みデータのID一覧を出力する。省略可能。デフォルトは無効
-o データを学習せず外れ値の計算だけやる。省略可能。デフォルトは無効

-dは-c,-s,-o,-tと排他
-sは-oと排他

anom_test.py

# -*- coding: utf-8 -*-

import signal
import argparse
import numpy as np
import matplotlib.pyplot as plt

from jubatus.anomaly import client
from jubatus.common import Datum

parser = argparse.ArgumentParser(description='This is jubaanomaly test tool')
parser.add_argument('name',                                help='data name')
parser.add_argument('-t', '--type',      dest='type',      help='type num_rules')
parser.add_argument('-c', '--clear',     dest='clear',     help='clear data',     action="store_true", default=False)
parser.add_argument('-s', '--save',      dest='save',      help='save or not',    action="store_true", default=False)
parser.add_argument('-d', '--display',   dest='display',   help='save or not',    action="store_true", default=False)
parser.add_argument('-o', '--only_calc', dest='only_calc', help='only calc',      action="store_true", default=False)

args = parser.parse_args()


def display_result(rdata, idata):
    dpoint = 5
    idx = 0
    result = dict()
    inf = float("inf")
    for i in idata:
        print(i, rdata[idx])
        if rdata[idx] != inf:
            result[i] = round(rdata[idx], dpoint)
        idx += 1

    plt.plot(list(result.keys()), list(result.values()), 'o')
    plt.title(u'Outliers')
    plt.show()


def connect_srv():
    try:
        anom = client.Anomaly("127.0.0.1", 9199, args.name)
        if args.clear:
            anom.clear()
    except:
        err_fin('failed to connect to server')
    return anom


def study_data(anom):
    idata = list()
    rdata = list()
    while True:
        try:
            line = float(input().strip())
            idata.append(line)
        except EOFError:
            break

        datum = Datum()
        if args.type == 'num':
            d_type = 'd1'
        elif args.type == 'str':
            d_type = 'd2'
        elif args.type == 'log':
            d_type = 'd3'
        datum.add_number(d_type, line)
        if args.only_calc:
            ret = anom.calc_score(datum)
#            print(ret)
        else:
            ret = anom.add(datum)
            #if (ret.score != float('Inf')) and (ret.score != 1.0):
            print(ret)
        rdata.append(ret)

    if args.save:
        anom.save(args.name)
    return rdata, idata


def do_exit(sig, stack):
    print('You pressed Ctrl+C.')
    print('Stop running the job.')
    exit(0)


def display_data(anom):
    try:
        data = anom.get_all_rows()
    except:
        err_fin(args.name + ' failed to get data')
    if not data:
        print(args.name + ' has no data')
    else:
        for i in sorted(data, key=float):
            print(i)


def err_fin(mes):
   print('Error: ' + mes)
   exit(1)


def chk_args():
    # -dと-c,-s,-n,-oは排他
    type_rules = ['num', 'str', 'log']
    if args.display and (args.clear or args.save or args.type or args.only_calc):
        err_fin('can not use -d with -c,-s,-o,-t')
    if args.save and args.only_calc:
        err_fin('can not use -s with -o')
    if not args.display and not args.type in type_rules:
        err_fin('invlid rule_type. ' + 'should be ' + ', '.join(type_rules))


if __name__ == '__main__':
    signal.signal(signal.SIGINT, do_exit)
    chk_args()
    anom = connect_srv()
    if args.display:
        display_data(anom)
        exit()
    else:
        rdata, idata = study_data(anom)
        if args.only_calc:
            display_result(rdata, idata)

使い方例

データを初期化してから学習させる(num_rulesのtypeはstr、学習データのファイル保存なし)

10個のデータを学習

$ seq 1 10 | python ./anom_test.py -c -t str test
id_with_score{id: 220, score: inf}
id_with_score{id: 221, score: 1.0}
id_with_score{id: 222, score: 0.9926380515098572}
id_with_score{id: 223, score: 1.0}
id_with_score{id: 224, score: 1.0065279006958008}
id_with_score{id: 225, score: 1.010113000869751}
id_with_score{id: 226, score: 0.9977192282676697}
id_with_score{id: 227, score: 0.993184506893158}
id_with_score{id: 228, score: 0.9930071830749512}
id_with_score{id: 229, score: 0.9959399700164795}

学習済みデータの確認

$ python ./anom_test.py -d test
220
221
222
223
224
225
226
227
228
229
$

外れ値計算 & 分布図出力

$ seq 1 10 | python ./anom_test.py -o -t str test
1.0 0.9999997615814209
2.0 0.9999999403953552
3.0 1.0
4.0 0.9999997615814209
5.0 0.9999998211860657
6.0 1.0
7.0 1.0
8.0 0.9999999403953552
9.0 1.0
10.0 1.0

f:id:pikesaku:20170709223633p:plain

jubatus anomalyのnum_rules動作検証(テストデータ分布状況出力ツール)

説明

データを受けてヒストグラムとパイチャートを出力
一次元データのみ対応。

dist_disp.py

# -*- coding: utf-8 -*-

import matplotlib.pyplot as plt


def make_pie_data(data):
    pie_data = dict()
    for i in data:
        pie_data[i] = data.count(i)
    return pie_data


def display_dist(data):
    # ヒストグラム生成
    plt.subplot(2, 1, 1)
    plt.hist(data, bins=50)
    plt.title(u'Input data histgram')

    # パイチャート生成
    pie_data = make_pie_data(data)
    plt.subplot(2, 1, 2)
    plt.pie(list(pie_data.values()), labels=list(pie_data.keys()))
    plt.title(u'Input data pie chart')

    # タイトルの被りを防ぐ
    plt.tight_layout()
    plt.show()


def get_data():
    data = list()
    while True:
        try:
            line = float(input().strip())
            data.append(line)
        except EOFError:
            break
    return data


if __name__ == '__main__':
    data = get_data()
    if data:
        display_dist(data)

使い方例

$ (seq 1 10;echo 1; echo 3) | python ./disp_dist.py

f:id:pikesaku:20170709214433p:plain

jubatus anomalyのnum_rules動作検証(テストデータ生成ツール)

説明

引数にデータ数、データのタイプ(以下参照)を指定し、データを生成するツール
・全部同じデータ
・一様分布
・標準正規分布
正規分布(平均50、標準偏差15)

make_data.py

# -*- coding: utf-8 -*-

import argparse
import numpy as np

parser = argparse.ArgumentParser(description='make data')
parser.add_argument('num_of_data',               help='num of data', type=int)
parser.add_argument('-t', '--type', dest='type', help='distribution type. zenbu_onaji or seiki1 or seiki2 or ichiyou', required=True)
args = parser.parse_args()


# 標準正規分布
def seiki1():
    for i in list(np.random.randn(args.num_of_data)):
        print(i)


# 正規分布
def seiki2():
    heikin = 50
    hensa = 15
    for i in list(np.random.normal(heikin, hensa, args.num_of_data)):
        print(i)


# 一様分布
def ichiyou():
    s = 1
    e = 100
    for i in list(np.random.uniform(s, e, args.num_of_data)):
        print(i)


# 全部同じ値
def zenbu_onaji():
    for i in range(args.num_of_data):
        print(1)


if __name__ == '__main__':
    if args.type == 'zenbu_onaji':
        zenbu_onaji()
    elif args.type == 'seiki1':
        seiki1()
    elif args.type == 'seiki2':
        seiki2()
    elif args.type == 'ichiyou':
        ichiyou()
    else:
        print('Error: invalid type')
        exit(1)

使い方例

$ python ./make_data.py 5 -t zenbu_onaji
1
1
1
1
1
$ python ./make_data.py 5 -t ichiyou
82.293075475
87.1943748063
84.6043656292
49.5115604224
90.631604143
$ python ./make_data.py 5 -t seiki1
-0.120117893927
0.786911376173
-1.0530541462
-0.3343056616
1.43960974838
$ python ./make_data.py 5 -t seiki2
35.7171926461
61.4762823277
56.6341546999
36.3448121399
63.7552040148
$ 

jubatus anomalyのnum_rules動作検証

目的

jubatus anomalyのnum_rules(typeがstr or num or log)の違いによる動作確認をする。

num_rulesのtypeの説明

データ変換 — Jubatus

上記URLによると以下の通り

意味
num 与えられた数値をそのまま重みに利用する。
str 与えられた数値を文字列として扱う。これは、例えばIDなど、数値自体の大きさに意味のないデータに対して利用する。重みは1とする。
log 与えられた数値の自然対数を重みに利用する。但し、数値が1以下の場合は0とする。

作成したツール

①make_data.py

データを生成する

pikesaku.hatenablog.com

②dist_disp.py

データの分布状況をヒストグラム・パイチャートで出力する

pikesaku.hatenablog.com

③anom_test.py

jubaanomalyにデータを投入する

pikesaku.hatenablog.com

Macでmatplotlibを使う

以下問題発生

$ cat ./test.py 
import numpy as np
import matplotlib.pyplot as plt

print("test")
$ python ./test.py 
Traceback (most recent call last):
  File "./test.py", line 2, in <module>
    import matplotlib.pyplot as plt
  File "/Users/pike/.pyenv/versions/3.5.0/lib/python3.5/site-packages/matplotlib/pyplot.py", line 115, in <module>
    _backend_mod, new_figure_manager, draw_if_interactive, _show = pylab_setup()
  File "/Users/pike/.pyenv/versions/3.5.0/lib/python3.5/site-packages/matplotlib/backends/__init__.py", line 32, in pylab_setup
    globals(),locals(),[backend_name],0)
  File "/Users/pike/.pyenv/versions/3.5.0/lib/python3.5/site-packages/matplotlib/backends/backend_macosx.py", line 19, in <module>
    from matplotlib.backends import _macosx
RuntimeError: Python is not installed as a framework. The Mac OS X backend will not be able to function correctly if Python is not installed as a framework. See the Python documentation for more information on installing Python as a framework on Mac OS X. Please either reinstall Python as a framework, or try one of the other backends. If you are using (Ana)Conda please install python.app and replace the use of 'python' with 'pythonw'. See 'Working with Matplotlib on OSX' in the Matplotlib FAQ for more information.

対策

以下ファイルを生成してOK

$ cat ./.matplotlib/matplotlibrc 
backend : TkAgg