前提・実現したいこと
現在、組織内の様々な場所で、様式がバラバラなExcel方眼紙(俗にいうネ申Excel)
が運用されています。その状態で、データの分析などを行うような風土にするという
圧力流れになってきているため、下記図のように、様々な様式から
一括でデータを抽出して、前処理などを実施し、一つのdataframeに集約
(した後、分析、可視化)しようと考えています。
発生している問題・エラーメッセージ
ただ、ネ申Excelですので、そのままセル位置を指定して、ハイそうですか、
とデータが抜けるものばかりではなく、
例えば、下図のように、データの前処理を行わないと必要なデータが取れない箇所があります。
(あくまで例として簡単なものを示しました)
そのため、パラメータファイルを用意して、そこにあらかじめ用意した前処理関数を指定することで、
必要な箇所に前処理を通すようにしようとしましたが、その際に、前処理関数を実行するため、Exec()
を使用したのですが、思うような動作になりません。(具体的には、前処理部分を通っているのに、
execが実行されてないような動作になります。)
そのため、execでは変数代入がきちんと動かないのではないかと思い、下記のような簡単な処理を書いてみたのですが、
この処理では数値が代入されるため、原因がわからない状態になっています。
execの動作確認に使用した簡易コード a = 1 b = 2 c = None d = None func = "extract_year_from_yyyymmdd" exec(f"c, d = {func}('{a}', '{b}')")
該当のソースコード
Python3
1 2def make_row_list_from_param(in_book, p_df): 3 """ 全パラメータの行値作成処理 4 parameterからDFを生成するための1行のリスト(値)を作成。あとでファイル単位で全シート分データを結合するために、ラベル名のリストもreturnする。 5 6 Args: 7 in_book (pandas.Excelfile): 抽出元ブックのオブジェクト(pandas) 8 p_df (pandas.DataFrame): パラメータデータのテーブル 9 Returns: 10 return_val_list(list): 各シート単位のパラメータ(値)のリスト 11 return_label_list(list): 各シート単位のパラメータ(表示ラベル)のリスト 12 return_column_list(list): 各シート単位のパラメータ(列名(df用))のリスト 13 """ 14 src_val = None 15 src_label = None 16 src_column = None 17 return_val_list = [] 18 return_label_list = [] 19 return_column_list = [] 20 in_data = in_book.parse(p_df.iloc[0].in_sheet_name, header=None) # in_sheet_nameがそろっている(1種類しかない)前提で0番目のシート名でparse(headerなし) 21 # print(data_src.iloc[2,7]) # test用 22 for i, data in enumerate(p_df.itertuples()): 23 if not data.pre_process is np.nan: # 前処理の関数が入っている場合 24 print(f"前処理関数が指定されているので、前処理:{data.pre_process}を実施します。") 25 execute_str = f"src_val, src_label = {data.pre_process}('{in_data.iloc[data.in_st_row-1,data.in_st_col-1]}', '{data.disp_label}')" 26 exec(execute_str) 27 src_val = [in_data.iloc[data.in_st_row-1,data.in_st_col-1]] # とりあえず前処理関数のやつはexecが正常動作しない(値を入れない)ので、後回し 28 src_label = [data.disp_label] # 29 src_column = [data.db_column] 30 print(f"実行の式:{execute_str}, 実行後の値:{src_val}, 実行後のラベル:{src_label}です。") 31 pass 32 else: 33 src_val = [in_data.iloc[data.in_st_row-1,data.in_st_col-1]] 34 src_label = [data.disp_label] 35 src_column = [data.db_column] 36 print(f"シート名:{p_df.iloc[0].in_sheet_name}で{data.in_st_row}行,{data.in_st_col}列のデータは{src_label}:{src_val}") 37 return_val_list += src_val 38 return_label_list += src_label 39 return_column_list += src_column 40 # print(i, data.db_table, data.db_column) 41 print(return_val_list, return_label_list) 42 return return_val_list, return_label_list, return_column_list 43 44def extract_qc_data_from_excel(file_list, sheet_list, param_df): 45 """ 品質データ抽出(excelから) 46 パラメータファイルに従い、品質データをexcelファイル(xls*)から抽出する。 47 :param file_list: 48 :param sheet_list: 49 :param param_df: 50 :return: 51 """ 52 result_list = [] # 最終結果のデータ格納用のリスト 53 label_list = [] 54 column_list = [] 55 for i, p in enumerate(file_list): 56 input_book = pd.ExcelFile(p) 57 # print(f"file:{p}") 58 val_list = [] 59 label_list = [] 60 column_list = [] 61 val_l = None 62 lbl_l = None 63 col_l = None 64 for sh in sheet_list: 65 # print(sh) 66 part_p = param_df.query(f"in_sheet_name==@sh") # queryは=ではなく==なので注意。代入ではなく比較 67 try: 68 val_l, lbl_l, col_l = make_row_list_from_param(input_book, part_p) 69 except (IndexError, ValueError) as e: 70 print(f"エラー:{e}, 直前の正常処理データ:{lbl_l[-1]}") 71 print(f"ファイル名:{p}は入力データ異常の為スキップします。") 72 continue 73 val_list = val_list + val_l 74 label_list = label_list + lbl_l 75 column_list += col_l 76 # part_p.in_st_row 77 # print(f"val_list:{val_list}, label_list:{label_list}") 78 79 # 各ファイルごとにdfの行を生成 80 duplicates_list = [k for k, v in collections.Counter(column_list).items() if v > 1] 81 if len(duplicates_list) >= 1: # 重複した要素が1つ以上ある場合 82 print(f"重複要素として、{duplicates_list}が検出されたので、終了します。") 83 break 84 85 result_list.append(val_list) 86 df = pd.DataFrame(result_list, columns=column_list) 87 df_label = pd.DataFrame(columns=label_list) 88 89 return df, df_label 90 91# メイン処理 92print("パラメータの読み込みモードを設定ください") 93# select_param_mode = "XXX" 94select_param_mode = input() 95print(f"{select_param_mode}") 96 97# paramater読込み 98folder_path = Path(select_param_mode) 99param_df = pd.read_excel("input_param.xlsx", sheet_name=select_param_mode, skiprows=1) 100param_df.head() 101 102sheet_list = param_df.in_sheet_name.unique() 103 104# ファイルからinput_paramに従い、各種データ読み込み(df化) 105file_list = [p for p in folder_path.iterdir() if p.is_file() and re.search(".xls", str(p)) and str(p.stem)[:2] != '~$'] 106 107df, df_label = extract_qc_data_from_excel(file_list, sheet_list, param_df) 108
試したこと
execの動作について確認した
関連サイトをチェックした
補足情報(FW/ツールのバージョンなど)
Python 3.8.7
pandas 1.3.0
回答3件
あなたの回答
tips
プレビュー