Python 指定列の要素に対して、部分一致によりデータをリストで抽出。それを用いて置換する方法「pandas」

'20/08/15更新:インデックス番号を1から振り直すコードを追記。また、備忘録の観点から、本記事の構成を再編集しました。

1. ある列を対象に部分一致したその行データを抽出したい場合
 df[df['列名'].str.contains('部分一致にしたい内容')]
 完全一致の場合は下記のようにする
 df[df['列名'] == '完全一致にしたい内容']
2. ある列のデータで並び替え(ソート)したい場合
 df.sort_values(['列名'], ascending=True)
3. indexをリセットして、古いのは削除したい場合
 df = df_sort.reset_index(drop=True)
4. インデックス番号を1から振り直したい場合
 df.index = np.arange(1, len(df2) + 1)
5. pandasデータフレーム書式の列をリストへ変換したい場合
 df['列名'].values.tolist()

 本プログラムによるデータ処理の例を示します。下図のようなcsvファイルがあって、列名は任意で、各列のデータは数値でも文字列でも構いません。

No Property Material
8 partA Fe
9 partB Ag
10 partC Al
14 partD Cu
15 partC Al
16 partE Au
1 partF Ag

本コードを実行すると、次の①~⑤でデータ処理します。
① 列名「Material」の中から、「Ag」がある行データを全て抽出
② ①で抽出した行データから、列名「Property」にある「partFとpartB」をリストで抽出
③ 列名「No」でソートを掛けて、9→1から1→9の順番に変換。ここで、csvファイルにも保存します。
④ そのリストに文字列を挿入

f:id:HK29:20200815113819p:plain

⑤ 最後に、下図左の@MY_TARGET_?@と記載してる箇所を下図右のように置換します。

f:id:HK29:20200329214120p:plain

▼本プログラム

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

# csvファイルからデータを抽出する関数
def extract_data(input_file, target_column_name, target_name,
                 sort_column_name, extract_column_name, sort_flag, i):
    
    # pandasのデータフレーム形式で読み込む
    df = pd.read_csv(input_file, encoding = "utf-8") 
    print(df)
    
    # 部分一致のデータ行を抽出
    df_extract = df[df[target_column_name].str.contains(target_name)]
    # 完全一致の場合
    #df_extract = df[df[target_column_name] == target_name]
    print(df_extract)
    
    # 指定列のソート(並び替え)
    df_sort = df_extract.sort_values(sort_column_name, ascending=sort_flag) 
    print(df_sort)
    
    # インデックスをリセット
    df2 = df_sort.reset_index(drop=True)
    # インデックスを1から振りなおす
    df2.index = np.arange(1, len(df2) + 1)
    print(df2)
    # csvファイルへ保存
    df2.to_csv(str('{0:02d}'.format(i)) + '_' + target_name + '.csv', index=True)
    
    # リストで抽出
    extract_list = df2[extract_column_name].values.tolist()
    print(extract_list)

    return extract_list

# 置換する文字列を作成して、リストへ格納する
def make_replace_list(extract_list):
    buf_list = []
    for i, data in enumerate(extract_list):
        buf_list.append('abcdef_' + str(data))
    print(buf_list)
    
    return buf_list

def main():
    for i, (target_name, target_string) in enumerate(zip(target_name_list, target_string_list)):
        # ファイルをバックアップして、順番に更新してゆく
        bacup_file_name = replace_file[:-4] + "_backup" + str(i) + '.txt'
        shutil.copy2(replace_file, bacup_file_name)
        
        # 置換するためのデータをリストで抽出する
        extract_list = extract_data(input_file, target_column_name, target_name,
                                    sort_column_name, extract_column_name, sort_flag, i)
        
        #(必要であれば)抽出したデータリストの全ての要素に文字列等を追記したリスト作成
        replace_list = make_replace_list(extract_list)
        
        # リストの各要素に改行コードを付与して、置換するために文字列へ変換
        replace_str = '\n'.join(replace_list)
        
        # 置換する
        with open(bacup_file_name, "r") as f2:
            with open(replace_file, "w") as f1:
                for row in f2:
                    if target_string in row:
                        f1.write(replace_str + '\n')
                    else:
                        f1.write(row)

if __name__ == '__main__':
    ### 抽出するファイルと項目の指定
    input_file = './data.csv'    
    target_column_name = 'Material'
    target_name_list = ['Ag', 'Al', 'Fe']
    extract_column_name = 'No'
    sort_column_name = 'No'

    ### 置換対象のファイルと文字列
    replace_file = './target.txt'
    target_string_list = ['@MY_TARGET_1@', '@MY_TARGET_2@', '@MY_TARGET_3@']
    
    sort_flag = True
    
    # call function
    main()
    print('finished')

関連記事は下記です。

hk29.hatenablog.jp

以上

<広告>