実現したいこと
説明変数に効果があるかどうかの解析を行いたくコードを実行していますが、説明変数リストが500個以上あり、実行終了に2時間以上かかっても終わりませんでした。具体的には、del_non_effective_explanatory_variable関数以降の処理が2時間以上経過しても終了しません。もっと高速に処理できる方法をご存じでしたら教えていただきたいです。
実行方法は以下のpythonファイルを実行します
※他にsql_select.pyとsql.pyというファイルが関係しているのですが、文字制限で添付不可
Python
1""" 2「タイトルの特徴」のPVに対する寄与度を回帰分析によって求める。 3本モジュールにはビジネスロジックを記述。 4目的変数Y = pv, facebookからのpv等 5説明変数X = 「特定キーワードを含む」場合1、その他0 etc 6単回帰分析で効果のある特徴を絞り込み→相関係数が高い特徴を削除→重回帰分析で効果検証。 7""" 8from builtins import float 9 10import psycopg2 11from pandas import read_sql 12from pandas.core.series import Series 13from pandas.core.frame import DataFrame 14from statsmodels.api import add_constant 15from statsmodels.api import OLS 16from sql import make_sql 17import sql_select 18 19#以下DB接続情報 20DB_HOST = '***' 21DB_NAME = '***' 22DB_PORT = '***' 23DB_USER = '***' 24DB_PSWD = '***' 25 26MAX_P = 0.1 # P値。この値より小さい場合を有意と認める上限値 27MIN_BETA = 0.05 # 回帰係数。この値より絶対値が大きい場合を効果ありと認める 28MAX_COR = 0.3 # 相関係数。この値より値が大きい場合を正相関ありとして片方の説明変数を除外する 29 30 31def output_result(xs: list) -> None: 32 """ 33 各説明変数ごとの該当数、回帰係数、P値、効果判定、増加率を標準出力。 34 35 @param xs: 説明変数情報リスト 36 """ 37 for x in xs: 38 print("{}\t{}\t{}\t{}\t{}\t{}".format(x["NAME"], x["COUNT"], x["BETA"], 39 x["P"], x["EFFECT"], x["RATE_OF_INCREASE"])) 40 41 42def ols_simple(y_data: Series, x_data: Series) -> tuple: 43 """ 44 単回帰分析を行い、該当件数と回帰係数とP値を求めてタプルにして返す。 45 46 @param y_data: 目的変数データ 47 @param x_data: 説明変数データ 48 @return: (該当件数, 回帰係数(β), P値(P)) 49 """ 50 num_match = list(x_data).count(1) # 該当数 51 52 x_data = add_constant(x_data, prepend=False) # 説明変数に定数項を加える 53 results = OLS(y_data, x_data).fit() # (Ordinary Least Squares: 最小二乗法) 54 55 for beta_value, p_value in zip(results.params.to_dict().items(), results.pvalues.to_dict().items()): 56 if beta_value[0] == p_value[0] and p_value[0] != "const": 57 return num_match, beta_value[1], p_value[1] 58 59 """ 60 単回帰分析の結果から説明変数の効果判定を行い、不要なものを削除した 61 DataFrame(df)と説明変数リスト(xs)を返す。 62 xs内のdictにはkeyとしてCOUNT, BETA, P, RATE_OF_INCREASE, EFFECTが追加される。 63 64 @param df: DataFrame 65 @param y_name: 目的変数データ名 66 @param xs: 説明変数情報リスト 67 @return: (修正されたdf, 修正されたxs) 68 """ 69 70def del_non_effective_explanatory_variable(df: DataFrame, y_name: str, xs: list) -> tuple: 71 df_tmp = df.copy() 72 xs_tmp = list(xs) 73 74 del_xs = [] # 効果がないので削除するxsの部分list 75 for x in xs_tmp: 76 count, beta, p = ols_simple(df[y_name], df_tmp[x["AS"]]) 77 x["COUNT"] = count 78 x["BETA"] = beta 79 x["P"] = p 80 x["RATE_OF_INCREASE"] = 10 ** x["BETA"] - 1 81 if x["P"] < MAX_P and x["BETA"] > MIN_BETA: 82 x["EFFECT"] = " +" 83 elif x["P"] < MAX_P and x["BETA"] < -MIN_BETA: 84 x["EFFECT"] = " -" 85 else: 86 x["EFFECT"] = "" 87 del_xs.append(x) 88 89 output_result(xs_tmp) 90 for dx in del_xs: 91 print("{} は効果がありません".format(dx["NAME"])) 92 del(df_tmp[dx["AS"]]) 93 xs_tmp.remove(dx) 94 return df_tmp, xs_tmp 95 96 97def del_high_corr_explanatory_variable(df: DataFrame, y_name: str, xs: list) -> tuple: 98 """ 99 説明変数どうしの相関係数をチェックして、MAX_COR以上の場合は片方を削除した 100 DataFrame(df)と説明変数リスト(xs)を返す。 101 Pが小さいを優先。|β|が大きいを第二優先。 102 103 @param df: DataFrame 104 @param y_name: 目的変数データ名 105 @param xs: 説明変数情報リスト 106 @return: (修正されたdf, 修正されたxs) 107 """ 108 df_tmp = df.copy() 109 xs_tmp = list(xs) 110 111 del(df_tmp["id"]) 112 del(df_tmp["title"]) 113 del(df_tmp[y_name]) 114 del_xs = [] # 相関が高いので削除するxsの部分list 115 for i, x in enumerate(xs_tmp): 116 for j, x2 in enumerate(xs_tmp): 117 if i < j and df_tmp.corr()[x["AS"]][x2["AS"]] > MAX_COR and x not in del_xs and x2 not in del_xs: 118 if x["P"] > x2["P"]: # Pが小さい方残す 119 print("『{0}』と『{1}』の相関が高いので、『{0}』を削除します".format(x["NAME"], x2["NAME"])) 120 del_xs.append(x) 121 elif x["P"] < x2["P"]: 122 print("『{0}』と『{1}』の相関が高いので、『{0}』を削除します".format(x2["NAME"], x["NAME"])) 123 del_xs.append(x2) 124 else: 125 if abs(x["BETA"]) > abs(x2["BETA"]): # Pが同一なら|β|が大きい方を残す 126 print("『{0}』と『{1}』の相関が高いので、『{0}』を削除します".format(x2["NAME"], x["NAME"])) 127 del_xs.append(x2) 128 else: 129 print("『{0}』と『{1}』の相関が高いので、『{0}』を削除します".format(x["NAME"], x2["NAME"])) 130 del_xs.append(x) 131 132 df_tmp = df.copy() 133 for dx in del_xs: 134 del(df_tmp[dx["AS"]]) 135 xs_tmp.remove(dx) 136 return df_tmp, xs_tmp 137 138 139def ols_multiple(y_data: Series, x_data: DataFrame) -> list: 140 """ 141 重回帰分析を行い、回帰係数とP値を求めて、list((変数名, 回帰係数, P値))を返す。 142 143 @param y_data: 目的変数データ 144 @param x_data: 説明変数データ 145 @return: (変数名, 回帰係数(β), P値(P)) 146 """ 147 x_data = add_constant(x_data, prepend=False) # 説明変数に定数項を加える 148 results = OLS(y_data, x_data).fit() # (Ordinary Least Squares: 最小二乗法) 149 150 beta_p_values = [] 151 for beta_value, p_value in zip(results.params.to_dict().items(), results.pvalues.to_dict().items()): 152 if beta_value[0] == p_value[0] and p_value[0] != "const": 153 beta_p_values.append((p_value[0], beta_value[1], p_value[1])) 154 return beta_p_values 155 156 157def update_xs_with_ols_multiple(df: DataFrame, y_name: str, xs: list) -> list: 158 """ 159 重回帰分析の結果からxs内dictのkey=(COUNT, BETA, P, RATE_OF_INCREASE, EFFECT)を更新して 160 xsを返す。 161 162 @param df: DataFrame 163 @param y_name: 目的変数データ名 164 @param xs: 説明変数情報リスト 165 @return: 修正されたxs 166 """ 167 xs_tmp = list(xs) 168 x_data_name_list = [] # 説明変数データ識別名のリスト 169 for x in xs_tmp: 170 x_data_name_list.append(x["AS"]) 171 results = ols_multiple(df[y_name], df[x_data_name_list]) 172 # xs_tmpの更新 173 for result in results: 174 for x in xs_tmp: 175 if result[0] == x["AS"]: 176 x["BETA"] = result[1] 177 x["P"] = result[2] 178 x["RATE_OF_INCREASE"] = 10 ** x["BETA"] - 1 179 if x["P"] < MAX_P and x["BETA"] > MIN_BETA: 180 x["EFFECT"] = " +" 181 elif x["P"] < MAX_P and x["BETA"] < -MIN_BETA: 182 x["EFFECT"] = " -" 183 else: 184 x["EFFECT"] = "" 185 return xs_tmp 186 187# 188# main 189# 190ys = list(sql_select.ys) # 目的変数のlist ex. {"SELECT": "log(pv_1w.pv + 1)", "AS": "pv"} 191for y in ys: 192 y_name = y["AS"] 193 print("■■ 目的変数 = {} ■■".format(y_name)) 194 xs = list(sql_select.xs) # 説明変数のlist 195 sql = make_sql(y, xs) 196# print(sql) 197 198 # DB → DataFrame 199 with psycopg2.connect(host=DB_HOST, database=DB_NAME, port=DB_PORT, user=DB_USER, password=DB_PSWD) as conn: 200 df = read_sql(sql, conn) 201 df, xs = del_non_effective_explanatory_variable(df, y_name, xs) # 単回帰分析でdf, xsから効果のない説明変数と対応データを削除 202 print("\n-------------------------------------------") 203 print("■ 相関係数のチェック") 204 df, xs = del_high_corr_explanatory_variable(df, y_name, xs) # 相関関数をチェックしてdf, xsを更新 205 print("\n-------------------------------------------") 206 xs = update_xs_with_ols_multiple(df, y_name, xs) # 重回帰分析で得られた結果でxsを更新 207 print("■ 重回帰分析の結果") 208 output_result(xs) 209 print("\n\n=========================================")
あなたの回答
tips
プレビュー