Python 指定列を対象に、抽出したい数値に近い値を抽出する「pandas」

'20/03/21更新:アルゴリズム変更とコードを見易く刷新した。
 下図のようなcsvファイルで、3列目の列名「Out」に数値が昇順に並んでいる。抽出したい値が例えば2.5の場合、2.5に近い値を抽出することを目的とする。

No In Out abc
1 21 1.2 a
2 32 1.24 b
3 42 1.41 c
4 58 1.72 d
5 91 1.933 e
6 99 2 f
7 115 2.22 g
8 132 2.67 h
9 148 2.81 i
10 165 2.91 j

 本プログラムの実行結果を下図に示す。2.5に最も近い値は2.22よりも2.67のため、2.67が抽出されている。その時のInの列の値も抽出してファイルに書き出す仕様とした。

f:id:HK29:20180402001748p:plain

一方、例えば、3を指定した場合は下図のようにNaNを返します。上記データの最大値は2.91であり、指定した3を一度も越えなかっただめである。

f:id:HK29:20200321122053p:plain
▼本プログラム

#!/usr/bin/env python3
# -*- coding:utf-8 -*-
import os, sys
import pandas as pd

def getTarget(value_list, target_val):
    for i in range(len(value_list)):
        if float(value_list[i]) > target_val:
            deltaA = float(value_list[i]) - target_val
            deltaB = target_val - float(value_list[i-1])
            if deltaA <= deltaB: # ターゲット値との差分を評価する
                return value_list[i]
            else:
                return value_list[i-1]
    if float(value_list[i-1]) < target_val: # ターゲット値を超えることがなかった場合
        return False

def main():
    df = pd.read_csv(input_path) # pandasのデータフレーム型で読み出す
    
    # 指定列をnumpyアレイ型で取得する
    value_np = df[target_column].values.T # ジャグ配列にしないため転置行列
    print (value_np, type(value_np))
    
    # 指定値に近い値を取得する
    got_value = getTarget(value_np, target_val) # 上記のgetTarget関数で処理
    print('got_value', got_value)
    
    # 近い値の行のデータを取得する
    if got_value: # 値がある場合に処理
        row_df = df[df[target_column] == got_value]  # 指定列の値とマッチした行を抽出する
        data1 = str(row_df[extract_column].values[0]) # その行にある抽出したい列の値を抽出する
        data2 = str(got_value)
    else:
        data1 = 'NaN'
        data2 = 'NaN'

    # ファイルに書き込むための文字列データの前処理
    data_str1 = ''.join([extract_column, '=', data1]) # リストから文字列作成
    data_str2 = ''.join([target_column, '=', data2])
    data_list = [data_str1, data_str2] # 文字列のリスト作成
    data_list_str = '\n'.join(data_list) # リストに要素毎に改行コードを入れて再び文字列化
    with open(out_path, 'w') as f:
        f.write(data_list_str) # 一気に書き込む
    
if __name__ == '__main__':
    input_path = os.path.join(os.getcwd(), "data.csv")

    target_column = "Out"
    target_val = 2.5
    extract_column = "In"
    out_path = 'get_abc.txt'
    
    main()

特記事項は、データ処理過程で、.Tで転置行列で一旦抽出した点である。そうしないとリストのリストとなり、扱いづらいためである。

   No   In    Out abc
0   1   21  1.200   a
1   2   32  1.240   b
2   3   42  1.410   c
3   4   58  1.720   d
4   5   91  1.933   e
5   6   99  2.000   f
6   7  115  2.220   g
7   8  132  2.670   h
8   9  148  2.810   i
9  10  165  2.910   j
[ 1.2    1.24   1.41   1.72   1.933  2.     2.22   2.67   2.81   2.91 ]

以上

<広告>