#author("2023-10-19T06:00:18+00:00","","") #author("2023-12-07T05:40:53+00:00","","") [[専門ゼミ(海野)]] ---- 目次 #contents ---- *目標 [#z00fd092] pymooというモジュールを使って多目的最適化問題を解きます。 釣り情報サイト(https://anglers.jp/)から富山湾の釣り場情報をスクレイピングする. *最適化問題とは [#h82a02b0] 最適化問題とは、制約を満たしつつ、目的の値を最大化or最小化する条件を求める問題のこと。 &br; 特に、目的関数が複数存在する最適化問題を多目的最適化問題という。&br; 多目的最適化問題を解く手法としてNSGA2があり、本ページではpythonでnsga2を用いて多目的最適化問題を解く方法を紹介する。 &br;&br; 最適化問題について学びたいときはこちら↓&br; https://science-log.com/%E6%95%B0%E5%AD%A6/%E3%80%90%E6%9C%80%E9%81%A9%E5%8C%96%E5%95%8F%E9%A1%8C%E3%81%AE%E5%9F%BA%E7%A4%8E%E3%80%91%E6%95%B0%E7%90%86%E6%9C%80%E9%81%A9%E5%8C%96%E3%81%A8%E3%81%AF%E4%BD%95%E3%81%8B/ &br; 多目的最適化とNSGA2について↓&br; https://logmi.jp/tech/articles/325211 *スクレピングとは [#h82a02b0] スクレピングとは,Webサイトから大量の情報を字と動的に抽出するコンピュータソフトウェア技術. &br; Webスクレイピングは、Webサイトやデータベースを探り、大量のデータの中から特定のデータのみを自動で抽出することができる.&br; *環境 [#h82a02b0] Python 3.10.1 64bitでやってますが,たぶんどのバージョンもできるはず...&br; pymooはバージョン0.5.0を使いましょう。 **プログラムの解説 [#s10f289d] ***準備 [#j661bc61] まず、pymooをインストールします。pymooはpythonでNSGA2を実行するためのモジュールです。&br; また、pymooはバージョンによってコードの書き方が変わります。&br; 自分は0.5.0を使っているので0.5.0をインストールする。&br; pip install pymoo == 0.5.0 Python 3.11 64bitで行う.(他でも可)&br; seleniumはバージョン4を用いる。 **準備 [#j661bc61] ***ChromeDriverのインストール [#j661bc61] まず、ChromeDriverをインストールする.自身のGoogleChromeのバージョンを確認し,それに合ったバージョンをインストールする. (https://chromedriver.chromium.org/downloads)。 ***seleniumのインストール [#j661bc61] seleniumをインストールする.バージョン3でもよいが,プログラムの書き方が異なる.&br; <pythonのとき> pip install selenium <notebookのとき> !python -m pip install selenium *実験 [#bb5c41a2] **問題設定 [#s10f289d] 以下の問題について考えてみる。 *動作実験(googleでの検索結果の取得) [#h82a02b0] **必要なモジュールをインポートする. [#h00fd477] from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.chrome.service import Service **driverのオプションを設定する. [#b380d497] options = webdriver.ChromeOptions() options.add_argument('--headless') options.add_argument('--no-sandbox') options.add_argument('--disable-dev-shm-usage') --headless ヘッドレスモード(バックグラウンドで起動) --no-sandbox sandboxモードを解除する(クラッシュ回避) --disable-dev-shm-usage パーティションが小さすぎることによる、クラッシュを回避する。 **chromedriverのパスを設定する. [#b380d497] インストールしたchromedriver.exeの場所を指定する. driver_path = "chromedriver-win64/chromedriver.exe" service = Service(executable_path=driver_path) **driverを作成する. [#b380d497] driver1 = webdriver.Chrome(service=service, options=options) driver1.implicitly_wait(10) --implicitly_wait(10) 指定した時間要素が見つかるまで待機. #ref(pro1.png,,400x220) **urlの情報を取得する. [#b380d497] url = "https://www.google.com/search?q=%E9%87%A3%E3%82%8A&oq=%E9%87%A3%E3%82%8A&gs_lcrp=EgZjaHJvbWUqCQgAEEUYOxiABDIJCAAQRRg7GIAEMgYIARAjGCcyBggCECMYJzINCAMQABiDARixAxiABDINCAQQABiDARixAxiABDINCAUQABiDARixAxiABDIGCAYQRRg9MgYIBxBFGD3SAQgxMTIxajBqNKgCALACAA&sourceid=chrome&ie=UTF-8" driver1.get(url) **XPATHを使って要素を取得して表示. [#b380d497] link = driver1.find_elements(By.XPATH, '//span/a/h3') for i in link: print(i.text) これは目的関数として (x1^2 + x2^2)を最小化かつ、(x1 - 1)^2 + x2^2 を最小化し &br; 制約条件として2(x1 - 0.1)(x1 - 0.9)/0.18 =< 0 、-20(x1 - 0.4)(x1 - 0.6)/4.8 =< 0 を満たしている問題について考えている。 *課題1 [#bb5c41a2] **すべて見るボタンをクリックしてスクレピングをする. [#s10f289d] &br; **サンプルプログラムの解説 [#s10f289d] #ref(pro1.1.py) 多目的最適化問題のコードの解説をする。&br; #ref(program.png,,550x700) all = driver1.find_element(By.XPATH, '/html/body/main/div[2]/div[4]/div[1]/div[1]/div[1]/a') driver1.execute_script('arguments[0].click();', all) &br; ***Myprogram全体の部分 [#s10f289d] ・class MyProgram(program): の中は最適化問題全体の計算するコードである。 &br; #ref(program1.png,,) 要素をクリックする.ここでall.click()としてもよいが,クリック場所が画面外の場合に要素をクリックすることができずエラーになることがある. &br; ***def __init__(self) [#s10f289d] def __init__(self): の中は最適化問題の引数の設定をしている。 #ref(program2.png,,) 引数の説明はこちら↓ &br; #ref(pro2.png,,400x220) また、__init__ についてはこちらを参考に↓ &br; https://qiita.com/ishigen/items/2d8b6e6398743f2c8110 &br; &br; ***evaluate [#s10f289d] evaluateの部分は目的関数と制約条件を書くところです。 &br; #ref(program3.png) *課題2 [#bb5c41a2] **さらに,それぞれの要素をクリックして釣り情報の詳細を取得する. [#s10f289d] out["F"]に評価関数の値,out["G"]に制約条件の値を書き込む。&br; ※制約条件、目的関数は=<0制約と設定してあるため、>=とする場合は-1をかける。&br; link = driver1.find_elements(By.XPATH, '/html/body/main/div/div/div[3]/div/a') syousai = [] for i in range(len(link)): driver1.execute_script('arguments[0].click();', link[i]) kikan = driver1.find_element(By.XPATH, '/html/body/main/div/div/div[2]/div[1]/div[2]/dl') syousai.append(kikan.text) driver1.back() link = driver1.find_elements(By.XPATH, '/html/body/main/div/div/div[3]/div/a') &br; ***プログラム実行部分 [#s10f289d] #ref(program4.png,,) 取得した情報をデータフレームに入れる import pandas as pd kirei = syousai[0].replace('\u3000', '').split('\n') syousai_df = pd.DataFrame([{'1' : kirei[i*2], '2' : kirei[i*2+1]} for i in range(int(len(kirei)/2))]) problem = MyProblem()で、記述した問題を定義。 &br; algorithm = NSGA2(pop_size=100)でアルゴリズムの種類を定義(本研究ではNSGA2を使用)&br; vurpose = True で処理の途中を可視化している(Trueで以下のように表示される)&br; #ref(program6.png,,360x360) n gen は現在の 世代数,n evel はこれまでの個体を評価した数,cv (min),cv (avg) はそれぞれ現在の母集 団における最小の制約違反,&br; 現在の母集団における平均の制約違反,n nds は多目的最適化問題の場合の非劣解の数,&br; eps は過去数世代にわたるインジケーターの変化,indicatorはパフォーマンスインジケーターを表す.&br; ***グラフ、解を表示する部分 [#s10f289d] #ref(program5.png) plot.の4行はNSGA2によって出力したパレート解を表示するコードである。&br; 表示されるグラフ↓&br; #ref(program7.png,,300x300) 最後の行はres.F,resXを表示している。 #ref(program8.png,,360x360) res.Fは、目的関数の値(ここでいうとres.Fはx1^2+xx2^2と(x1-1)^2+x2^2)、res.Xはその時のx1,x2の値を表示している。 補足&br; 最大化したい場合は2つの目的関数の符号を逆にしてください *課題 [#bb5c41a2] 実験用のサンプルプログラム(目的関数と制約条件が空白になっている)を変更する。&br; **問題設定 [#s10f289d] 以下の問題について考えてみる。 #ref(program13.png,,400x220) これは目的関数として (x1^2 + x2^2)を最小化かつ、(x1 - 1)^2 + x2^2 を最小化し &br; 制約条件として2(x1 - 0.1)(x1 - 0.9)/0.18 =< 0 、-20(x1 - 0.4)(x1 - 0.6)/4.8 =< 0 を満たしている問題について考えている。 &br; ***変更したプログラム [#s10f289d] &br; #ref(pro_sample.py) #ref(program12.png,,400x300) ***グラフ、解を表示する部分 [#s10f289d] #ref(program11.png,,500x300) *参考文献 [#ddfa4bf2] pymoo公式サイト(日本語訳をして見てね)&br; https://pymoo.org/algorithms/moo/nsga2.html &br; pymooの使い方まとめ&br; https://yuyumoyuyu.com/2021/07/23/howtousepymoo/