日々精進

新しく学んだことを書き留めていきます

DataFrameの値を書き換えるときにSettingWithCopyWarningが出る

df['age'][5]のように[]を二段にしてアクセスすると発生する。これはchained indexingと呼ばれ、やってはいけない。 df.loc['age', 5]のように.locを使えば回避できる。 この警告が出る理由は以下に詳しく書かれているので是非読むことをオススメします。 日本語で詳細な解説が読めるとは、ありがたや~

linus-mk.hatenablog.com

Bitvise SSH Serverにログインすると直後に接続が切れる

sshサーバのログには以下のメッセージが出ていた。

  <event seq="52" time="2019-05-02 20:41:20.671086 +0900" app="BvSshServer 7.21" name="W_SESSION_DISCONNECTED_ABNORMALLY" desc="Session disconnected abnormally.">
    <session id="1006" service="SSH" remoteAddress="192.168.0.100:59781"/>
    <parameters disconnectReason="FlowError"/>
    <error type="Flow" component="SshManager/transport/kexHandler" class="Flow" code="ComponentException" description="Exception in component: Windows CNG (x64) with additions: AsymKey: CngAgree: unexpected secretData-&gt;cbStruct"/>
  </event>

原因はBitvise SSH Serverの不具合で、Windowsのバージョンが1803以降だとログインできなくなるらしい。 Bitvise SSH Serverをバージョンアップすると直った。

参考:

stackoverflow.com

pandas.qcutはcutする列の値に重複があると挙動がおかしくなることがある

現象は以下。

  • TitanicのtrainデータのAgeの欠損値を22.0で埋める
  • pd.qcut(train["Age"], 4, duplicates="drop").value_counts() を実行すると以下のようになり、要素数にかなり偏りができる
(0.419, 22.0]    408
(24.0, 35.0]     220
(35.0, 80.0]     217
(22.0, 24.0]      46
Name: Age, dtype: int64

「境界値をずらすともっと偏るのでしょうが無い」という状況なのかなと思いきや、そうでもなく、例えば以下の方が良い分割方法のように見える。

pd.qcut(train["Age"], [0, .2, .5, .75, 1.], duplicates="drop").value_counts()

(20.0, 24.0]     275
(24.0, 35.0]     220
(35.0, 80.0]     217
(0.419, 20.0]    179
Name: Age, dtype: int64

これはpandasの不具合なんだろうか。。値の重複があるときはqcutを使わないようにするか。。

JupyterNotebookで親階層のモジュールをimportする方法

ディレクトリ階層が以下のようになっている場合。 grand_parent_dir > parent_dir > child_dir parent_dir/init.pyに書いている関数をimportして使いたいとする。 child_dirの下にJupyterNotebookがあるとする。 その場合、JupyterNotebookで以下のように書いても読み込めない。

from ..parent_dir import func

Jupyterは親階層のファイルを読み込めないため。(多分セキュリティ的な問題で) でも以下のようにsys.pathにpathを追加すると読み込めるようになる。 注意点としては、parent_dirまでのpathを追加してもだめで、grand_parent_dirまでのpathを追加しないといけない。 でないとparent_dir/init.py内の関数をimportできなかった。

import sys, os
from pathlib import Path
sys.path.append(str(Path(os.path.dirname(os.path.abspath("__file__"))).parent.parent))

参考:

stackoverflow.com

DataFrameの型指定をしてサイズを削減する手順を自動化

以前の記事でDataFrameの各列の型を指定してサイズを小さく出来ると書いたが、それを自動化する。

anton0825.hatenablog.com

以下を使ってcsvを読み込むとサイズを自動的に削減してくれる。一度全部読み込んでから型変換しているので、 処理途中で使うメモリ量は増える。csvはこれを使ってDataFrameに変換した後、Feather形式で保存し以降はそれを使うようにするといい。

def read_csv(filename: str, verbose: bool = True) -> pd.DataFrame:
    # Seriesの型を最適なものにすることでメモリを削減する。
    # float16はFeather形式で保存出来ないため使用しない。
    df: pd.DataFrame = pd.read_csv(f"{INPUT_PATH}/{filename}")
    start_mem: float = df.memory_usage().sum() / 1024 ** 2
    for col in df.columns:
        _set_optimized_type(col, df)
    end_mem: float = df.memory_usage().sum() / 1024 ** 2
    _print_result(end_mem, start_mem, verbose)
    return df


def _print_result(end_mem: float, start_mem: float, verbose: bool):
    if verbose:
        reduce_percent: float = 100 * (start_mem - end_mem) / start_mem
        print('Mem. usage decreased to {:5.2f} Mb ({:.1f}% reduction)'.format(end_mem, reduce_percent))


def _set_optimized_type(col: str, df: pd.DataFrame):
    numerics: List[str] = ['int16', 'int32', 'int64', 'float32', 'float64']
    col_type: List[str] = df[col].dtypes
    if col_type in numerics:
        if str(col_type)[:3] == 'int':
            df[col] = df[col].astype(_to_optimized_int_type(df[col].min(), df[col].max()))
        else:
            df[col] = df[col].astype(_to_optimized_float_type(df[col].min(), df[col].max()))


def _to_optimized_int_type(c_min: int, c_max: int):
    if np.iinfo(np.int8).min < c_min and c_max < np.iinfo(np.int8).max:
        return np.int8
    elif np.iinfo(np.int16).min < c_min and c_max < np.iinfo(np.int16).max:
        return np.int16
    elif np.iinfo(np.int32).min < c_min and c_max < np.iinfo(np.int32).max:
        return np.int32
    elif np.iinfo(np.int64).min < c_min and c_max < np.iinfo(np.int64).max:
        return np.int64


def _to_optimized_float_type(c_min: float, c_max: float):
    if np.finfo(np.float32).min < c_min and c_max < np.finfo(np.float32).max:
        return np.float32
    else:
        return np.float64

参考:

qiita.com