Cucco’s Compute Hack

コンピュータ関係の記事を書いていきます。

seabornを使ってみた

seabornを使ってみた。
plt.show(block=False) # これがないと表示されない。block=Falseがないとグラフを閉じるまでプログラムの実行が一時停止する。

ソースコード
import numpy as np
import seaborn as sns
from matplotlib import pyplot as plt

x = np.random.normal(size=100) 
iris = sns.load_dataset("iris")

sns.distplot(x, kde=False, rug=False, bins=10)
plt.show(block=False) # これがないと表示されない。block=Falseがないとグラフを閉じるまでプログラムの実行が一時停止する。


sns.pairplot(iris)
plt.show(block=False)

# プログラムの終了とともにプロット画面も閉じてしまうので入力まち
input()
結果

f:id:Cucco:20200327183347p:plain
distplotの結果

f:id:Cucco:20200327183425p:plain
pairplotの結果

NasneからNASへの移行(速報版)

とりあえず最低限の目途はついたので、NasneからNASへのデータ移行メモ。
用途としては、録画データの延命。Nasneは古くなっていて、いつ壊れてもおかしくないので。

まだNasneからコピーしていない録画番組を選んでコピーや、コピーした番組の番組名ごとのディレクトリ分けのスクリプトPythonで作成。もう少しきれいにしてから掲載予定。

移行先のNAS

QNAPのTS-453be。本体5万強。HDD別。4本必要。
TS-453Be - 機能 | QNAP

追加購入のQNAP NASのアプリ。sMedio DTCP Move。税込み1100円。
sMedio DTCP MOVE

iPhoneでの再生環境用 税込み 1300円。
Media Link Player for DTV ~スマホでテレビを見よう~

できないこと
  • NASにコピーした番組は、NASから再移動できない。DTCP-IPとかDLNAとかの仕組みの範囲で、wifiのある範囲なら再生できる。
  • NASの装置自体が壊れたら(装置を交換したら)、録画データは再生できない。
できること
  • NasneからNASに番組をコピー(ダビング10ならコピー制限数が減っていく)
  • HDDが壊れた時のRAIDの再構築(推定)
  • iPhoneでの視聴
標準ではできないこと
  • コピー候補の番組を絞り込むこと。
    • 録画した月やジャンルでの絞り込みはできる。
    • 番組名で検索してコピー候補の絞り込みはできない。
  • まだNasneからコピーしていない番組を選んでコピーすること。
  • 全件の一括コピー。「Nasneのデータを全件コピーしろ」という操作はできるのだが、150件くらいしかコピーされなかった。(※1)
スクリプトで解決できたこと
  • まだNasneからコピーしていない録画番組を選んでコピーすること。ただし※1を避けるため、100件単位。
  • コピーした番組の番組名ごとのディレクトリ分け。手動で番組名に含まれる名前のフォルダを作っておく必要あり。
スクリプトで解決できてないこと
  • まだNasneからコピーしていない録画番組を選んで全件をコピーすること。(移動の処理中かどうかを正しく検出できないので)
試行錯誤メモ
  • iPhoneのDiXiM Playは、モバイル向けの解像度を半分にしたトランスコード版なら再生できる。
    • NasneNASに移動の操作をする際に設定すればトランスコード版で移動できる。
    • sMedio DTCP Moveにはトランスコード機能はないらしく、コピー後にあとからトランスコードできない。
    • データ容量はだいたい1/4になる。
    • DiXiM Playでも設定が必要で、「再生判定を厳しくする」をオフに。

iPhoneのバックアップ先をDドライブへ

iPhoneのバックアップデータがCドライブの容量を食うので、iTunesが書き込むiPhoneのバックアップ先のディレクトリをDドライブに移動させる話。(公式ではないので自己責任で)

手順

大まかには、シンボリックリンクをつかって、iTunesが書き込むiPhoneのバックアップ先のディレクトリを別のドライブのディレクトリに化かす。
Windows10 Windowsストア版のiTunesむけ。

  1. 既存のバックアップディレクトリを、別のドライブにコピーする。
  2. 既存のバックアップディレクトリをリネームする(最終的には削除する)
  3. 既存のバックアップディレクトリから、別のドライブへのシンボリックリンクを作る
01. 既存のバックアップディレクトリを、別のドライブにコピーする。

既存のバックアップディレクトリ: "C:\Users\<ユーザディレクトリ名>\Apple\MobileSync\Backup"
から、
別のドライブ: "D:\keep\iTunesBackup"
に既存のバックアップファイルをコピーする。

robocopy /MIR "C:\Users\<ユーザディレクトリ名>\Apple\MobileSync\Backup" "D:\keep\iTunesBackup"

コピー完了後に、既存のバックアップディレクトリと別のドライブの容量やファイル数が一致することを確認する。

02. 既存のバックアップディレクトリをリネームする(最終的には削除する)

この後、既存のバックアップディレクトリと同名のシンボリックリンクを作るので、既存のバックアップディレクトリはなんでもいいので、別名にしておきます。

既存のバックアップディレクトリ: "C:\Users\<ユーザディレクトリ名>\Apple\MobileSync\Backup"
リネーム後: "C:\Users\<ユーザディレクトリ名>\Apple\MobileSync\Backup-old"

03. 既存のバックアップディレクトリから、別のドライブへのシンボリックリンクを作る

以下を、管理者として実行します。

mklink /d "C:\Users\<ユーザディレクトリ名>\Apple\MobileSync\Backup" "D:\keep\iTunesBackup"

最後に

iTunesiPhoneのバックアップを取る。別のドライブにあるバックアップファイルが更新されていればOK。

openpyxlで、エクセルファイルのフィルタの設定をする

openpyxlで、エクセルファイルのフィルタの設定をする実証コード

エクセルで開いても、フィルタの設定は入っているが、フィルタ表示はされていない状態で表示される。
エクセルで開いて、フィルタのプルダウンを開いて、再適用すれば、フィルタリングされた状態で表示される。

コード
from openpyxl import Workbook, load_workbook, utils

# 1行目がヘッダで、A2からデータが入っている想定
read_filename = r"C:\dev\SampleCodes\hello_openpyxl\NATO_phonetic_alphabet.xlsx"
save_filename = read_filename.replace(".xlsx", "_filterd.xlsx")
wb = load_workbook(read_filename)

# 対象シートは 'Sheet1'
ws = wb['Sheet1']

# フィルタを設定したい列名を指定
filter_col = 'A'
# column_index_from_string(A)は1を返すが、使うときはオフセットで0始まりなので1を引いておく。
filter_col_offset = utils.column_index_from_string(filter_col) - 1
print("filter_col = {0}, filter_col_offset = {1}".format(
    filter_col, filter_col_offset))

# 表示したい行にある、A列の内容
# 実際にはない値を指定しても、add_filter_columnでは無視される。
filter_words = ["0", "A", "Z"]

# データがある最大行を取得
max_row = ws.max_row
max_col = ws.max_column
print("max_row = {0}, max_col = {1}".format(max_row, max_col))

# 表示したい値が、実際にあるか確かめておく
for word in filter_words:
    flag_find = False

    for row_index in range(0, max_row):
        cell_value = ws.cell(
            row=row_index+1, column=utils.column_index_from_string(filter_col)).value
        if word == str(cell_value):
            flag_find = True
            print("{0} in filter_words found".format(word))
            break

    if flag_find == False:
        print("Error!! {0} in filter_words not found".format(word))
        exit(-1)

# 列番号をxlsの列名アルファベットに変換
max_col_letter = utils.cell.get_column_letter(max_col)

# filterの範囲を指定
# A列からデータがあることが前提。
ws.auto_filter.ref = "A1:" + max_col_letter + str(max_row)
print("ws.auto_filter.ref = {0}".format(ws.auto_filter.ref))

# filter指定
# filter_col_index は 0だと、ws.auto_filter.refの範囲で、いちばん左の列
ws.auto_filter.add_filter_column(filter_col_offset, filter_words)
# サンプルコードにあったソートはしなくてよい。
# https://openpyxl.readthedocs.io/en/latest/filters.html#using-filters-and-sorts
# ws.auto_filter.add_sort_condition("B2:B15")

# 保存はする。
# エクセルで開いても、フィルタの設定は入っているが、フィルタ表示はされていない状態で表示される。
# エクセルで開いて、フィルタのプルダウンを開いて、再適用すれば、フィルタ表示される。
wb.save(save_filename)

wb.close()
実行結果
(base) C:\dev\SampleCodes\hello_openpyxl>python hello_filter.py
filter_col = A, filter_col_offset = 0
max_row = 37, max_col = 2
0 in filter_words found
A in filter_words found
Z in filter_words found
ws.auto_filter.ref = A1:B37

(base) C:\dev\SampleCodes\hello_openpyxl>
読んでいる元データ

NATO_phonetic_alphabet.xlsx

f:id:Cucco:20191018222930p:plain
読んでいる元データ

順位を教えてくれる関数

順位を教えてくれる関数。
データ件数に対してn^2で計算時間がかかるようなので、大きな配列への適用は難しい。

自前環境での計算時間は大体以下の通り。
# 10000個で、0.2秒
# 20000個で、0.7秒
# 30000個で、1.5秒
# 40000個で、2.7秒

プログラム

import numpy as np
import random
import time

# 1次元配列を渡したら、その配列の中での大きい順(一番大きな値に対しては1)を返してくれる関数。
#
# 10000個で、0.2秒
# 20000個で、0.7秒
# 30000個で、1.5秒
# 40000個で、2.7秒


def calc_rank(data):
    np_data = np.array(data)
    rank = [None]*len(data)

    for index, value in enumerate(data):
        rank[index] = np.sum(np_data >= value)

    return rank


def rand_list(length):
    rl = [None]*length

    for index in range(length):
        rl[index] = random.randrange(0, length*2)

    return rl


if __name__ == "__main__":
    # data=[0,12,53,9,31,78,40,87,84,55,20,77]
    length = 1000
    data = rand_list(length)

    tic = time.time()

    rank = calc_rank(data)

    toc = time.time()
    print("データ件数", length)
    print("計算時間(秒)", toc-tic)

    print("計算結果抜粋")
    for i in range(len(data)):
        print("{0} {1}".format(data[i], rank[i]))
        if i > 5:
            break  # 印字は邪魔なので適当にbreak

実行結果

データ件数 12
計算時間(秒) 0.0
計算結果抜粋
0 12
12 10
53 6
9 11
31 8
78 3
40 7
87 1
84 2
55 5
20 9
77 4

Cisco スイッチコマンド備忘録

gwがスイッチの名前です。

Terminal(CUI関係)

terminal length 0

--More-- が出てくるときに。0にすれば全部一括で表示される。行数を指定できる。

DHCP関連

DHCPのリリース状況確認
show ip dhcp binding
固定IPの割り当て
configure
ip dhcp pool pool_sample
import all
host 192.168.11.2 255.255.255.0
hardware-address 0123.4567.89AB
dns-server 192.168.1.1
client-name pool_sample
default-router 192.168.1.1
lease infinite
end

hardware-addressは、DHCPのリリース状況確認で確認できる。
hardware-addressは、client-identifier となることもある。その時は、01+MACアドレス、のような値になっている。

自動割り当てされたIPの解除(MAC重複解除)
clear ip dhcp binding 192.168.11.2

よく使うのは、hardware-address を割り当てようとして、以下が出てきたときなど。

% A binding for this client already exists. 

アクセスリスト関係

WAN側のInerfaceに設定すべきアクセスリスト
https://blog.redbox.ne.jp/cisco-acl-cbac.html

アクセスリストの設定

アクセスリストの設置場所、方向の話
アクセスリストを理解する

現在の設定のエクスポート(USBメモリを刺した状態で)

customer-config という名前のファイルでUSBメモリに保存される。

copy running-config usbflash0:customer-config

リモートアクセスVPN

Ciscoの資料。ステップ18 [ハッシュ アルゴリズム MD5 を使用してパスワードを暗号化する]のチェックを解除 をしないとつながらない。
https://community.cisco.com/t5/cisco-start-%E3%83%89%E3%82%AD%E3%83%A5%E3%83%A1%E3%83%B3%E3%83%88/%E3%83%AA%E3%83%A2%E3%83%BC%E3%83%88-%E3%82%A2%E3%82%AF%E3%82%BB%E3%82%B9-ipsec-vpn-%E3%82%92%E8%A8%AD%E5%AE%9A%E3%81%99%E3%82%8B/ta-p/3292247

リストの結合と、DBへの格納

長さが同じリストを、列が増える方向に連結して、DBに格納する検証コード。
Pandasを経由したほうが、SQLでのテーブル定義 をしなくてもよいから楽

プログラム

import pandas as pd
import sqlite3

# 長さが同じListを、列が増える方向に連結
# Index は無しで、DBに入れる。

# -------------------------------------------
# 結合
x = [1, 2, 3, 4, 5]
y = ['a', 'b', 'c', 'd', 'e']
z = [1.1, 2.2, 3.3, 4.4, 5.5]

# name はDBの列名になる。
s_x = pd.Series(data=x, name="x")
s_y = pd.Series(data=y)
s_y.name = "y"
s_z = pd.Series(data=z)

# axis=0 行を増やす方向に連結
axis = 0
df1 = pd.concat([s_x, s_y], axis=axis)
print(df1, type(df1))

# axis=1 列を増やす方向に連結
axis = 1
df1 = pd.concat([s_x, s_y], axis=axis)
print(df1, type(df1))

df2 = pd.concat([s_x, s_y], axis=axis)
print(df2, type(df2))

df3 = pd.concat([s_x, s_y, s_z], axis=axis)
print(df3, type(df3))

# -------------------------------------------
# DB書き込み

con = sqlite3.connect(":memory:")
con.isolation_level = None  # None で自動コミットモード
cur = con.cursor()
cur.execute('PRAGMA temp_store=MEMORY;')
cur.execute('PRAGMA journal_mode=MEMORY;')

# DBへの書き込み df3を書き込み。インデックスは無し。
table_name = 'test_table'
df3.to_sql(name=table_name, con=con, index=False)

# テーブル定義の確認
tmp = cur.execute("SELECT * FROM sqlite_master WHERE type='table'")
print("# テーブル定義の確認")
for row in tmp:
    print(row)

# 書き込んだの内容の確認
tmp = cur.execute("SELECT * FROM {0}".format(table_name))
print("# テーブルの内容の確認")
for row in tmp:
    print(row)

con.close()

実行結果

(base) C:\>python C:\hello_pandas\hello_concat.py
0    1
1    2
2    3
3    4
4    5
0    a
1    b
2    c
3    d
4    e
dtype: object <class 'pandas.core.series.Series'>
   x  y
0  1  a
1  2  b
2  3  c
3  4  d
4  5  e <class 'pandas.core.frame.DataFrame'>
   x  y
0  1  a
1  2  b
2  3  c
3  4  d
4  5  e <class 'pandas.core.frame.DataFrame'>
   x  y    0
0  1  a  1.1
1  2  b  2.2
2  3  c  3.3
3  4  d  4.4
4  5  e  5.5 <class 'pandas.core.frame.DataFrame'>
# テーブル定義の確認
('table', 'test_table', 'test_table', 2, 'CREATE TABLE "test_table" (\n"x" INTEGER,\n  "y" TEXT,\n  "0" REAL\n)')
# テーブルの内容の確認
(1, 'a', 1.1)
(2, 'b', 2.2)
(3, 'c', 3.3)
(4, 'd', 4.4)
(5, 'e', 5.5)