20211016のPythonに関する記事は22件です。

辞書

辞書 dic_sample.py gakkyu_iin={ '1組':'alfred', '2組':'beck', '3組':'charlie'} print(gakkyu_iin) # → {'1組': 'alfred', '2組': 'beck', '3組': 'charlie'} と出力される #値の書き換え gakkyu_iin['1組']='anna' #値の追加 gakkyu_iin['4組']='daisy' print(gakkyu_iin) # → {'1組': 'anna', '2組': 'beck', '3組': 'charlie', '4組': 'daisy'} と出力される
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

辞書型

今回の授業資料 また本日の授業のサンプルコード (以下で列挙したコードであるdic_sample.pyと前回記事 array_sample.pyを合算したpython3ファイル) を,まなBOXにアップしています.演習や授業の参考としてご活用ください. 辞書 dic_sample.py gakkyu_iin={ '1組':'alfred', '2組':'beck', '3組':'charlie'} print(gakkyu_iin) # → {'1組': 'alfred', '2組': 'beck', '3組': 'charlie'} と出力される #値の書き換え gakkyu_iin['1組']='anna' #値の追加 gakkyu_iin['4組']='daisy' print(gakkyu_iin) # → {'1組': 'anna', '2組': 'beck', '3組': 'charlie', '4組': 'daisy'} と出力される
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

完全未経験が【Aidemy Premium Plan】を受講した感想

はじめに プログラム未経験なホテルマンが一からAidemyにてAIを学習した感想になります。 本記事の目的 本記事は全く未経験からAidemyを受講してみようと考えている方の参考になるよう書かれています。 Aidemy Premium Planとは Aidemyは人工知能分野に特化したプログラミングスクールです。 特徴としては 数学の知識が不要 環境構築の必要がない メンターとのマンツーマン指導 完全オンラインで学習 カリキュラム外の講座も受けることができる 専門実践教育訓練給付金対応 といった未経験の方が学習しやすいサービスとなっています。 学習内容の感想 カリキュラム、学習スタイルの感想です。 カリキュラム 1.Python入門 2.ライブラリ「NumPy」基礎(数値計算) 3.ライブラリ「Pandas」基礎(表計算) 4.ライブラリ「Matplotlib」基礎(可視化) 5.データクレンジング 6.データハンドリング 7.機械学習概論 8.教師あり学習(回帰) 9.教師あり学習(分類) 10.教師なし学習 11.時系列解析I(統計学的モデル) 12.機械学習におけるデータ前処理 13.ディープラーニング基礎 14.自然言語処理基礎 15.感情分析/株価予測 16.タイタニック(kaggleのコンペ) 学習スタイル 1~2時間ぐらいにコンテンツがまとまっており、 コンテンツごとに演習問題に挑むことになります。 コンテンツごとにある添削問題ではGoogle Colaboratoryを使い回答することになります。 ブラウザのみで学習が完結するためハイスペックなパソコンは不要です。 良かった点 完全未経験から実装まで一気通貫に学習することができた。 Slackでのサポート 人工知能学習に用いるPythonという言語を全く知らない状態から、実際にプログラムを組むまで一つの流れで学習するので違和感なく学習することができます。 学習のサポートとしてメンターとのマンツーマンでのサポートの他にも、Slackを用いていつでもメンターに質問することができます。 このため実質24時間質問に対応していただけます。 悪かった点 やや密度の薄い教材 基礎から実践まで全てを教えるため一つ一つのコンテンツが希薄になりがちです。 添削問題への回答にコンテンツ以外の内容も使うことも多く、自身での学習が必須となります。 Pythonに関してはProgateやPyQというサイトを利用して学習を行いました。 実際にデータを分析してみる ギリシャにおける宿泊満足度調査 総合的な満足度を立地やサービスなどの満足度から導き出します。 データについて ハーバード大学が公開してるデータセットを使います 実行環境 Google Colaboratoryを利用しました。 モジュールをインポート import pandas as pd import numpy as np from sklearn.model_selection import train_test_split from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Activation, Dense, Dropout, Input, BatchNormalization from sklearn.metrics import mean_squared_error データの取り込み シートごとに分割したエクセルファイルをGoogle driveに用意し取り込みます。 from google.colab import drive drive.mount('/content/drive') df1 = pd.read_excel('/content/drive/MyDrive/Colab Notebooks/成果物用データ/Book1.xlsx') df2 = pd.read_excel('/content/drive/MyDrive/Colab Notebooks/成果物用データ/Book2.xlsx') df3 = pd.read_excel('/content/drive/MyDrive/Colab Notebooks/成果物用データ/Book3.xlsx') df4 = pd.read_excel('/content/drive/MyDrive/Colab Notebooks/成果物用データ/Book4.xlsx') エクセルを結合し内容を確認 df = pd.concat([df1, df2, df3, df4]) df データの修正 Book1のみoverall_rateが10分の1になっていたため修正し結合しなおします。 df1['overall_rate'] = df1['overall_rate'] * 10 df = pd.concat([df1, df2, df3, df4]) df データの取得 読み込んだデータからデータを取得 今回は総合の満足度を表すoverall_rateを他の数値を使って予想します。 df = df.drop(['stars', 'rate_characterization'] , axis=1) X = df.drop(['overall_rate'], axis=1) Y = df['overall_rate'] モデルの学習 データを学習しやすいように整え、学習のためのモデルを構築し学習します。 X = (X - X.mean(axis=0)) / X.std(axis=0) X_train, X_test, y_train, y_test = train_test_split(X, Y, test_size=0.25, random_state=42) model = Sequential() model.add(Dense(10, input_dim=10, activation='relu')) model.add(Dense(16, activation='relu')) model.add(Dense(1)) model.compile(loss='mse', optimizer='adam') history = model.fit(X_train, y_train, epochs=100 , batch_size=16 , verbose=1, validation_data=(X_test, y_test) ) 結果をみる y_pred = model.predict(X_test) mse= mean_squared_error(y_test, y_pred) print("REG RMSE : %.2f" % (mse** 0.5)) こうして機械学習ができました。 必要であればここから更に調整を行いより精度の良いモデルを構築します。 今後の活用 今まで人工知能を使わずに行っていた顧客の行動分析が簡単におこなえるようになった。 オープンデータとして公開されていないようなデータを収集し、新たな分析をしていきたい。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

競プロ典型90問 004 - Cross Sum

問題 競プロ典型90問 004 - Cross Sum 考察 全探索を考える あるAn,mに対してのBn,mを求める計算量を考えます。 計算量は同じ行と同じ列の数字を全て足すのでH+Wになります。 そして全てのAn,mに対してこの計算を行うのでH × W × (H+W)となって間に合いません。(制約内の最大値で考えると1.6*10^10になってしまう) 各行と列の合計を先に出して仕舞えば良いのでは 行と列の合計を先に求めることによって An,mがある行と列の合計を足してAn,mを引く計算をするだけでBn,mが求められる。 ソース H,W = map(int,input().split()) A = [[0]*W for i in range(H)] hSum = [0] * H vSum = [0] * W for i in range(H): workA = list(map(int,input().split())) for j in range(W): vSum[j] += workA[j] hSum[i] = sum(workA) A[i] = workA for i in range(H): ans = [0] * W for j in range(W): ans [j] = hSum[i] + vSum[j] - A[i][j] print(" ".join(list(map(str,ans)))) Python3だとTLEになってしまうようなのでPyPy3で提出しました。 調べてみるとPython3でもできないことはないようですが上位の人でもギリギリみたいなのでPyPy3で提出するのが無難かなと思いました。 最後に ★2ということですぐに方針はたったのですが、一度コードを書いた時に縦の列と横の列を足しただけのコードを書いてしまい、An,mが2回足されてしまうのを見落としてしまいました。 考察時点で気づけそうなミスには気をつけていきたいですね。 テストで気づけばまだ良いのですが、たまたま入力例がうまくいくパターンだった場合WAしてしまいますし。 次回の記事に関してですが、★6,★7はみてみたところ手も足も出なさそうだったので一度飛ばそうと思っています。次回の記事は006 - Smallest Subsequencになるかと思います。 それでも今までで最高難易度の★5なので心してかかりたいと思います。 以上、最後まで読んでいただきありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pythonで正規分布と戯れる

はじめに E資格の次は統計検定の合格を!ということで、早速Pythonで統計について理解を深めていきたい。そこでまずは正規分布と戯れてみた。 正規分布とは 以下の確率密度関数で定義される分布である。 $$ f(x) = \frac{1}{\sqrt{2πσ^2}} \exp(-\frac{(x-u)^2}{2σ^2}) $$ 確率密度関数をPythonで書いてみよう。 腐るほど、いろんな人がやったネタであるが、自分で書いてみよう。 確率変数Xと平均と分散を受け取って確率を返すというもの。 numpyなので複数のXに対して計算できちゃうぞ。 # 正規分布関数 def normal(x, u, v): ret = 1 / np.sqrt(2 * np.pi * v) * np.exp(-(x-u)**2/(2*v)) return ret 描画してみよう 先ほどの関数を使って平均0、分散1の標準正規分布を書いてみよう。 # matplotlibで描画 x = np.linspace(-5, 5,100) y = normal(x, 0, 1) fig = plt.figure(figsize=(5,5)) ax = fig.add_subplot(1,1,1) ax.plot(x, y) するとこんな感じ。もう腐るほどみた図だと思う。 モンテカルロ法により面積を求めてみよう さて、確率密度関数というのは、-∞から∞まで積分すると1になるはずだ。 積分は大変なので、今回これをモンテカルロ法により求めてみよう。 モンテカルロ法とは、確率変数のサンプリングをコンピューター上で行うことで、数学的な問題を数値的に解く手法である。 今回は一様分布を用いる。 百聞は一見に如かずで、まずはXについて[-5, 5]、Yについて[0, 0.4]にの一様分布に従うX, Yを生成・プロットし、その上に先ほどの確率密度関数を重ねてみよう。 # -5~5までの間で一様にXを生成 randomX = -5 + np.random.rand(30000) * 10 # 0~0.4までの間で一様にYを生成 randomY = np.random.rand(30000) * 0.4 fig = plt.figure(figsize=(10,10)) ax = fig.add_subplot(1,1,1) ax.scatter(randomX, randomY) ax.plot(x, y, c="r") そうするとこんなプロットが得られるはずだ 今、関数の下側の面積を求めたいわけだから、ランダムに領域内にプロットされた点の内、確率密度関数より下側にある点の割合を求め、領域全体面積(10 * 0.4)を掛ければよい。 ※ -5~5の範囲外の確率はほぼ0近いので無視していることに注意してほしい。 コードは下の通りである。 upperCount = 0 #上にあるか lowerCount = 0 #下にあるか for i, (randomX_tmp, randomY_tmp) in enumerate(zip(randomX, randomY)): normalY = normal(randomX_tmp, 0, 1) if randomY_tmp < normalY: lowerCount += 1 else: upperCount += 1 print(lowerCount, upperCount, (lowerCount / len(randomX)) * 10 * 0.4) 計算すると1.008とほぼ1に近い値が得られた。 562 22439 1.0082666666666666 おわりに 次回からは様々な分布を取り扱っていきたい。 統計学の本は非常に抽象的に記載されているので、Pythonを使って具体的なイメージに落とし込んでいきたい。乞うご期待。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

競プロ典型90問 003 - Longest Circular Road

問題 競プロ典型90問 003 - Longest Circular Road 考察 スコアの最大値とは スコアは2都市間の距離+1となります。 つまり、スコアの最大値を求めるには2都市間の距離の最大値を求めれば良い。 2都市間の最長の距離を求めるためにどうすれば良いか 今回、N都市間にN-1本の道路があるので各都市間の行き方は1通りしかありません。よって、 最長距離になる2都市をAq,Bqとすると、任意の都市から最も遠い都市はAq,Bqのどちらかになります。 そこで、AqとBqの間の距離を求めるために まず、ある任意の都市から1番遠い都市を求めます。(これがAqかBqのどちらか) そこから一番遠い都市との距離を求めればそれが2都市間の最長距離になります。 ではある都市からの最長距離をどのように求めるか ここは全然わからなかったのでググりました。 BFS(幅優先探索)やDFS(深さ優先探索)というものがあるらしいです。 幅優先探索は最短距離を調べるのに良いみたいです。とりあえず今回は深さ優先探索を使ってみました。 深さ優先探索は先に行けるところまで探索して行けるところがなくなると一歩戻って探索するというようなアルゴリズムです。 ソース 都市の番号ごとに繋がる都市を配列に読み込みます。 そして、都市1から一番遠い都市を探し出し、その都市から一番遠い都市との距離を求めます。 import sys sys.setrecursionlimit(10**7) N = int(input()) connect = [[] for i in range (N+1)] for i in range(N-1): A,B = map(int,input().split()) connect[A].append(B) connect[B].append(A) distance = [0] * (N+1) def dfs(now,pre,dist): distance[now] = dist for i in connect[now]: if i != pre: dfs(i,now,dist+1) dfs(1,-1,0) maxdis = max(distance) for i in range(len(distance)): if distance[i] == maxdis: workCity = i break distance = [0] * (N+1) dfs(workCity,-1,0) print(max(distance)+1) もう少し処理をまとめて、都市の番号だけ渡すような関数を作ったらよかったかなと思いました。 あと、最初の提出で下の処理を maxdis = max(distance) for i in range(len(distance)): if distance[i] == maxdis: workCity = i break 下のように書いてしまい、TLEをくらいました。 解説読んでも方針合っててDFS使うのも合ってるし、なんでだ?とめちゃくちゃ混乱しました。こういうミスは減らしていかないとですね。 for i in range(len(distance)): if distance[i] == max(distance): workCity = i break 最後に どうやって最長の2都市を探すかという方針は割と早めに立ったのですが、DFS等の探索するアルゴリズムを知らなかったため、ある都市からの距離を求めるという工程の実装にかなり時間がかかってしまいました。 とはいえ、あれこれ考えていたけどとりあえずDFSのコードの例を探してきて同じように書いてみればすぐACすることができたのであれこれ考える前に方針が立ったらコードを書いてみないとなと思いました。 相変わらずアルゴリズムの知識不足と実装力不足が課題ですが、競プロ典型90問をやることで解消していけないかなと思っています。 以上、最後まで読んでいただきありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

AtCoderで入緑するために必要だったアルゴリズムとデータ構造 (2021年10月版)

みなさん初めまして 初登校です? 少し前になりますが、2021/10/2に行われたABC221で入緑しました!? 今回は私が入緑するのに必要だったアルゴリズムとデータ構造についてまとめていこうと思います. よろしくお願いします. はじめに AtCoder緑の現状について 例のchokudaiさんの記事だけではなく, 実はAtCoder内に未完成情報ですが こんな記事 があったりします. 共通して 競技プログラミングを熱心に取り組んでいるユーザと考えて問題なく、他社のアルゴリズム能力判定サイトでは、最高ランクに到達出来る水準です。 と記載があり, 簡単なものではないことに変わりありません. なぜ2021年10月版を作るのか? 最近のAtCoder界隈は平均レベルがあがっている1部分があり,緑になるのにも要求されるレベルがあがっていると感じている人が一定数いるようです.2 またABCが8問体制になり問題の難易度の崖が緩やかになるなど,環境が変わってきているので現在の情報をまとめたかったため作成しました. 自己紹介 普段は業プロer(web)として自社サービスのバックエンド/フロントエンドを中心に開発しています. (Rails/React) AtCoderをやる上で周りをみると強い人が大量にいますね. 一言で入緑といっても強い人は一瞬で到達していくので,そうではない私の場合を簡単に記載します. AtCoderを始めたのがアラサーになってからで,始めてから入茶するまでに10ヶ月ほどかかっている. 入茶してから入緑するまでに6ヶ月ほどかかっている. (入緑までに合わせて1年4ヶ月かかっている) 学歴は偏差値50くらいの理工系学部卒(非情報系, ちなみに理数系科目苦手だった) 持ってるIT系資格はFEとAP 統計情報をもとにしてはいませんが, 界隈の中では強い方ではありません.ご安心ください. 入緑した際のStatsは, はてぶの方に書いたので気になる方はそちらをどうぞ 使用言語, 開発環境 言語 Python3(Pypy)で取り組んでいます. 始めたときには業プロでPython使っていたのでその流れで選びました. 言語が異なると言語仕様によって利用できるライブラリ等で難易度に違いがでるので, Pythonだとそうなんだな~程度にお考え下さい. lower_boundはデフォで持っててほしいよPythonさん... 開発環境 正直パフォーマンスには関係ないのですが記載しておくと, Windows10+WSL2(Ubuntu)+Docker+VSCode(RemoteDevelopment) で取り組んでいます. CLIで済むと楽だと気づいたので, online-judge-toolsとatcoder-cliを使ってコンテストの生成からテストと提出までをCLIで行っています. 学習/使用したアルゴリズム アルゴリズム 理解度 使用 使用した問題 線形全探索 ○ ○ ABC214-B など bit全探索 ○ × 二分探索 ○ ○ ABC212-C 順列/組み合わせ/包除原理 ○ ○ ABC215-C 累積和 ○ ○ ABC220-C imos法 ○ ○ ABC221-D 基礎DP ○ ○ ABC220-D 耳DP ○ ○ ABC211-C DFS △ ○ ABC213-D BFS △ ○ ABC211-D トポロジカルソート △ × 約数列挙 ○ × GCD/LCM ○ ○ ABC215-D エラトステネスの篩 ○ × 座標圧縮 ○ ○ ABC213-C 転倒数 △ × 幾何要素 ○ ○ ABC197-D グラフ理論に関するアルゴリズムは基礎BFS,DFSができれば足りると思います. (経路復元はできなくてもなんとかなる) 経路復元できないって経路探索アルゴリズムちゃんと理解してないよね? はい精進します... あとDijkstra法,ワーシャルフロイド法と言った最短経路を求めるアルゴリズムは使えなくても大丈夫でした. 3 学習/使用したデータ構造 データ構造 理解度 使用したか 使用した問題 queue ○ ○ ABC211-D priority-queue ○ ○ ABC212-D HashTable ○ ○ ABC218-D Union-Find Tree △ × 一番重要なのはqueueです. 次に重要なのはHashTableです. それぞれTLEを防ぐ上で重要なデータの持ち方になります. Union-Find Treeは何度かコンテスト中に問題に出会ったのですが,結局1度も解けませんでした... 学習方法 問題を解きながら, 分からない問題は解説ACをしてアルゴリズムを身に着けて行きました. 主に AtCoderProblems の - Bootcamp or Beginners: Easy - Bootcamp or Beginners: Medium そして 競プロ典型90問 (☆3まで) を解きました. そして,非常に重要なのはコンテスト後に挑んで解けなかった1問を解くことです. 緑diff以下の解けなかった問題を解説ACするようにしていました. 余談ですがアルゴリズムのメモやAtCoderの自分の取り組んだ問題管理にはNotionを使っています. オススメです. やらなかったこと(必要なかったこと) 自作ライブラリ/スニペットの作成 緑になった現在はUnion-Find Treeのライブラリを作りましたが, 入緑に限っては特にライブラリを作る必要はなかったです. 同じく早解きの観点からスニペットを用意して参戦する方も多いと思いますが, 現時点ではなくても何とかなっています.(いずれ作る予定です) 競プロ関連書籍による勉強 蟻本/螺旋本/けんちょん本と買ってあるのですが積読状態になってしまっています. 書籍による知識のベースを埋め込まなくても, 精進の中で解説を見てアルゴリズムが理解できてoutputできているうちは優先しなくてもよさそうに思います. 典型90で行き詰ったら手を付けていく予定です. グラフ理論に関する書籍での勉強 例題で学ぶグラフ理論/グラフ理論入門の2冊を買ってあるのですが積読状態になっています. グラフ理論に関して全く得意意識がないので入水に向けて重点的に取り組む必要があると思っていますが, 緑までだったらなくても大丈夫でした. AtCoder以外の競プロ AOJもCodeForcesもyukicoderもやりたいなと思ってますができてません. さいごに 入緑したい~! と思っている方の少しでも参考になれば幸いです. 私は入水を目指してこの後も精進を続けます. 初投稿なので非礼や誤りがありましたら申し訳ありません.ぜひご指摘ください. また疑問質問もありましたらコメントお待ちしています. ありがとうございました! 諸説あります ↩ けんちょんさんのtweetでも言及があったりします ↩ もちろん使えた方がいいです ↩
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

kivyMDチュートリアル其の参什捌 Components - Selection篇

ハロー、Qiita!いかがお過ごしでしょうか。 今週も相変わらず、KivyMDの触れ込みをやっております。お時間ありましたら お付き合いください。 ニュース的には、特にとりとめもないのですが、変わったことでいうと衆議院 解散くらいでしょうか。まさかの政治ネタが2週間連続という。投票結果がどう なるかということをデータ分析で予想するというのも面白そうですね。私は、 知識がおぼつかず見ているだけになりそうですが... ということで今週も元気にやっていきましょう。今週はSelection篇となります。 Selection マテリアルデザインのリンクは見ておいて頂けたらと思います。 マニュアルの最初の説明は以下のようになっています。 Selection refers to how users indicate specific items they intend to take action on. ここも個人の考え方をいれないよう、依頼をしてみます。 選択とは、ユーザーが行動を起こすための具体的な項目を示すことです。 選択 = Selection となっている以外はどうでしょうか。んー、このまま説明されても少し抽象的かなと 思われるかもしれません。あとは、英語の部分は英語のままに翻訳するというのは 難しそうですね。ある程度その知識を知らないと、英語のエキスパートの方でも 翻訳を間違えそう... ということでこの説明がなんなのか分かるためにも先へ進みましょう。すぐ下の キャプチャを見るとなんとなく分かる気もしますが。 Entering selection mode selection modeへ入れるということでしょうか。ここで、Selectionコンポーネント はselection modeというのがあるのが分かります。実装の方は後に出てくるので一旦 そこは飛ばします。 で、また説明がありますね。 To select an item and enter selection mode, long press the item: なにやら、selection modeにするにはアイテムを長押しする必要があるらしいです。 キャプチャはそのまま長押しをして、selection modeを入れていますね。 Exiting selection mode 今度はselection modeを出る、すなわちselection modeをoffにするということで しょうか。こちらも説明があります。 To exit selection mode, tap each selected item until they’re all deselected: モードを出る、オフにするときにはもう一度アイテムをタップすればよいということ でしょうか。これもキャプチャはそのままのことを指しています。 Larger selections こちらは以下のように、まだ機能がないよとありますね。 This feature is missing yet. Events 説明というかUsageみたいなコードでは2つのイベントがあるよと示されています。 def on_selected(self, instance_selection_list, instance_selection_item): '''Called when a list item is selected.''' def on_unselected(self, instance_selection_list, instance_selection_item): '''Called when a list item is unselected.''' on_(un)selectedメソッドがそれぞれ、Entering/Exiting selection mode となるということでしょうか。これも後のサンプルコードで出てくるでしょう。第2 引数にselection_listのインスタンス、第3引数にselection_itemのインスタ ンスがあるんだろうなとしか現状わかりません。 Example with TwoLineAvatarListItem ということで、まずは最初のサンプルコードになります。こちらは全文を掲載する こととします。 xxxviii/selection_with_listitem.py from kivy.animation import Animation from kivy.lang import Builder from kivy.utils import get_color_from_hex from kivymd.app import MDApp from kivymd.uix.list import TwoLineAvatarListItem KV = ''' <MyItem> text: "Two-line item with avatar" secondary_text: "Secondary text here" _no_ripple_effect: True ImageLeftWidget: source: "data/logo/kivy-icon-256.png" MDBoxLayout: orientation: "vertical" MDToolbar: id: toolbar title: "Inbox" left_action_items: [["menu"]] right_action_items: [["magnify"], ["dots-vertical"]] md_bg_color: 0, 0, 0, 1 MDBoxLayout: padding: "24dp", "8dp", 0, "8dp" adaptive_size: True MDLabel: text: "Today" adaptive_size: True ScrollView: MDSelectionList: id: selection_list spacing: "12dp" overlay_color: app.overlay_color[:-1] + [.2] icon_bg_color: app.overlay_color on_selected: app.on_selected(*args) on_unselected: app.on_unselected(*args) on_selected_mode: app.set_selection_mode(*args) ''' class MyItem(TwoLineAvatarListItem): pass class Example(MDApp): overlay_color = get_color_from_hex("#6042e4") def build(self): return Builder.load_string(KV) def on_start(self): for i in range(10): self.root.ids.selection_list.add_widget(MyItem()) def set_selection_mode(self, instance_selection_list, mode): if mode: md_bg_color = self.overlay_color left_action_items = [ [ "close", lambda x: self.root.ids.selection_list.unselected_all(), ] ] right_action_items = [["trash-can"], ["dots-vertical"]] else: md_bg_color = (0, 0, 0, 1) left_action_items = [["menu"]] right_action_items = [["magnify"], ["dots-vertical"]] self.root.ids.toolbar.title = "Inbox" Animation(md_bg_color=md_bg_color, d=0.2).start(self.root.ids.toolbar) self.root.ids.toolbar.left_action_items = left_action_items self.root.ids.toolbar.right_action_items = right_action_items def on_selected(self, instance_selection_list, instance_selection_item): self.root.ids.toolbar.title = str( len(instance_selection_list.get_selected_list_items()) ) def on_unselected(self, instance_selection_list, instance_selection_item): if instance_selection_list.get_selected_list_items(): self.root.ids.toolbar.title = str( len(instance_selection_list.get_selected_list_items()) ) Example().run() 少し長いので、今日は久しぶりに小分けにして触れ込みたいと思います。 import文 さっそくこちらに入っていきます。 from kivy.animation import Animation from kivy.lang import Builder from kivy.utils import get_color_from_hex from kivymd.app import MDApp from kivymd.uix.list import TwoLineAvatarListItem 目新しいのはAnimationとget_color_from_hexオブジェクトではないでしょうか。 ただし、AnimationはBehaviorsのところになるので、ここでは詳細は端折ります。 ちなみに、get_color_from_hexについてはクラス側にて登場します。 kv側 打って変わり、kv側に入ります。 KV = ''' <MyItem> text: "Two-line item with avatar" secondary_text: "Secondary text here" _no_ripple_effect: True ImageLeftWidget: source: "data/logo/kivy-icon-256.png" MDBoxLayout: orientation: "vertical" MDToolbar: id: toolbar title: "Inbox" left_action_items: [["menu"]] right_action_items: [["magnify"], ["dots-vertical"]] md_bg_color: 0, 0, 0, 1 MDBoxLayout: padding: "24dp", "8dp", 0, "8dp" adaptive_size: True MDLabel: text: "Today" adaptive_size: True ScrollView: MDSelectionList: id: selection_list spacing: "12dp" overlay_color: app.overlay_color[:-1] + [.2] icon_bg_color: app.overlay_color on_selected: app.on_selected(*args) on_unselected: app.on_unselected(*args) on_selected_mode: app.set_selection_mode(*args) ''' こちらに関して言えば、特に目新しいところというとMDSelectionListとなる でしょうか。それ以外に関しては、以下ページもしくはマニュアルの方をご覧に おなり下さい。あとは、kv側を見てマニュアルともしくは動かしてみて、ここが 該当するんだね〜と照らし合わせるのも面白いかと。 MDSelectionListはというと、今回の大目玉となりますね。これだけ見ると 特に変わった形はしていないと思われます。overlayはselection modeに 入ったときに変わる色となります。ですが、overlay_colorプロパティの値 である計算式は少し不明というのが現状です。また分かり次第、お知らせする かもしれません。 on_(un)selectedプロパティに関しては先述のEventのところでありましたね。 プロパティ自体は記載がありませんでしたが、実体(メソッド)が書かれていました。 値にその実体となるコールバックメソッドを指定しています。on_selected_mode もおなじようにコールバックメソッドを置いています。 あとは細かいところですが、on_selectedプロパティのコールバックメソッドで 指定するメソッドで多変数引数をこのように指定することも必見でしょうか。 クラス側 残りはクラス側となります。こちらも抜粋します。 class MyItem(TwoLineAvatarListItem): pass class Example(MDApp): overlay_color = get_color_from_hex("#6042e4") def build(self): return Builder.load_string(KV) def on_start(self): for i in range(10): self.root.ids.selection_list.add_widget(MyItem()) def set_selection_mode(self, instance_selection_list, mode): if mode: md_bg_color = self.overlay_color left_action_items = [ [ "close", lambda x: self.root.ids.selection_list.unselected_all(), ] ] right_action_items = [["trash-can"], ["dots-vertical"]] else: md_bg_color = (0, 0, 0, 1) left_action_items = [["menu"]] right_action_items = [["magnify"], ["dots-vertical"]] self.root.ids.toolbar.title = "Inbox" Animation(md_bg_color=md_bg_color, d=0.2).start(self.root.ids.toolbar) self.root.ids.toolbar.left_action_items = left_action_items self.root.ids.toolbar.right_action_items = right_action_items def on_selected(self, instance_selection_list, instance_selection_item): self.root.ids.toolbar.title = str( len(instance_selection_list.get_selected_list_items()) ) def on_unselected(self, instance_selection_list, instance_selection_item): if instance_selection_list.get_selected_list_items(): self.root.ids.toolbar.title = str( len(instance_selection_list.get_selected_list_items()) ) Example().run() MyItemクラスはどのクラスを継承させるかということで定義されています。 本節で名前が記載のある通り、TwoLineAvatarListItemが継承されています。 そして残るは、Exampleクラスになりますがこちらはメソッドごとに触れ込んで いきたいと思います。よくあるbuildメソッドについては端折ります。 あ、あと忘れていましたが、overlay_colorは選択状態になったときの色を 指定しています。ここでは紫っぽい色を指定しています。 on_start on_startメソッドになります。これも一旦抜粋してみます。 def on_start(self): for i in range(10): self.root.ids.selection_list.add_widget(MyItem()) ここに関しては、kv・クラス側で記載しているMyItemをオブジェクト生成して います。for文である通り、10個のリストアイテムが得られます。 set_selection_mode 同様、こちらも抜粋してみます。 def set_selection_mode(self, instance_selection_list, mode): if mode: md_bg_color = self.overlay_color left_action_items = [ [ "close", lambda x: self.root.ids.selection_list.unselected_all(), ] ] right_action_items = [["trash-can"], ["dots-vertical"]] else: md_bg_color = (0, 0, 0, 1) left_action_items = [["menu"]] right_action_items = [["magnify"], ["dots-vertical"]] self.root.ids.toolbar.title = "Inbox" Animation(md_bg_color=md_bg_color, d=0.2).start(self.root.ids.toolbar) self.root.ids.toolbar.left_action_items = left_action_items self.root.ids.toolbar.right_action_items = right_action_items まず、if-elseであるのが、modeで条件を定めていることと名前からもある通り selection modeの設定となりますね。まずselection modeであれば、over- lay_colorを背景(md_bg_colorプロパティに代入)に設定してleft/right_ action_itemsにアイコンなどを差し替えます。left/right_action_items プロパティがなんなのか分からない方はもう1度Toolbar篇をご覧ください。 # elseについては初期画面のときの設定になりますね それらが終わると、アニメーションをして、left/right_action_itemsそれ ぞれに設定したものを設定しておきます。 あと、少し漏れているところというと、言わずもがなですがcloseアイコンのとき は全て選択状態をクリアするようなコールバックメソッドを指定しています。 on_selected/on_unselected これらはほとんど同じようなので、まとめておきます。で、同じように抜粋をして みます。 def on_(un)selected(self, instance_selection_list, instance_selection_item): if instance_selection_list.get_selected_list_items(): # unselectedのときだけ self.root.ids.toolbar.title = str( len(instance_selection_list.get_selected_list_items()) ) 設定する内容としてはほとんど同じようなものです。どちらも、選択状態のとき、 ツールバーのタイトルにリストアイテムの長さを逐一取得するということになる かと思われます。ただし、on_unselectedメソッドのときは、instance_se- lection_listのget_selected_list_itemsメソッドが有効のときにその設 定をしているという事がわかります。 これをしないとどうなるか結果の方で見てみましょう。 結果 はい、というわけで少し触れ込みが長くなりましたが、一旦この辺で動作を見る ことにします。と言ってもマニュアルで大方動作も見れますが。。 まずは、正常なところから。 特に問題がないようですね。ほぼマニュアルと同じ挙動です。 で、あとはon_unselectedメソッドに関してのところで、ifの条件をなくすと どうなるか試してみたところ動作的には問題がなさそうです。まぁこれもprint デバッグしてわかったことですが、get_selected_list_items()は選択状態 のリストアイテムオブジェクトを取得しています。 なのでこれがあり次第ということなのですが、これはmodeとかを条件にできない のか...と15秒くらい考えにふけていました。ですが、仕様に関しては我々が口 出しできません。これはこれでと思うしかありません。 # ご指摘はじゃんじゃんお寄せ頂ければ嬉しいです! Example with FitImage というわけで、一区切りはついたのですが、こちらもあるのでさくさく進んでいき たいと思います。 コードも触れ込みたいところではあるのですが、これといってとりとめもありません。 差分はちらちらある状況ではあるんですけどね。これも理由がありまして、なんと、 コンポーネントにFitImageが加わりました! 喜ばしいことは間違いありません、が、なんだかなぁ、、んー、これは言葉に出せない ことですね。。 ともあり、FitImageに関してはまた別の機会ということにします。完全にこれはkivy 側の方かと思っていました。 ということなので、メインの差分をここで触れておきます。それが何なのかということ になるのですが、progress_round_colorになりますね。これは選択モードへ入るとき にグルグルする円マークみたいなものがありました。まさしく、名前の通りですね。 とりあえず、コードについてはほとんどとりとめもなくなったので端折ります。 結果 はい、ということで本日最後の動作確認となります。さっそく見ていきましょう。 最近顔馴染みのところから画像を出力してみました。引用元としては以下となります。 これもマニュアルと比較すると問題ないようすですね。途中消そうとしているけど... 少しその後、色あたりを見ていて触ったりしているのでGitHubのコードは変わって いるかもしれませんが、ご了承頂ければと思います。まぁ変化点がどこにあるのか みることもよいかもしれませんね。 API - kivymd.uix.selection.selection ということで、まとめに入る前にAPIの方をおさらいしておきます。 class kivymd.uix.selection.selection.MDSelectionList(**kwargs) kv・クラス側両方に出てきたウィジェットですね。 Events on_selected Called when a list item is selected. on_unselected Called when a list item is unselected. イベントとしては2つありましたね。使い方は両方とも同じようなものです。 selected_mode List item selection mode. If True when clicking on a list item, it will be selected. selected_mode is an BooleanProperty and defaults to False. 今度はプロパティになります。このプロパティはon_selected_modeプロパティの コールバックメソッドの引数で自動的に呼ばれるものでした。あれっ、名前違うくね? となった方はするどい。鋼の錬金術師だとにらみつけられる立ち位置にいそうです。 # キャラの名前わすれた そうです、引数としてはmodeと呼ばれていました。ただし、これは引数なので、 プロパティ名としてはこれで合っている可能性はありますね。ただ、どちらが正しい かと言われるとんーとなる次第です。。もしかするとプロパティの設定がいらないもの なのかも。 icon Name of the icon with which the selected list item will be marked. icon is an StringProperty and defaults to ‘check’. icon_pos The position of the icon that will mark the selected list item. icon_pos is an ListProperty and defaults to []. icon_bg_color Background color of the icon that will mark the selected list item. icon_bg_color is an ColorProperty and defaults to [1, 1, 1, 1]. icon_check_color Color of the icon that will mark the selected list item. icon_check_color is an ColorProperty and defaults to [1, 1, 1, 1]. これらはアイコン関連のプロパティになりますね。使用していないものもありますが、 アイコン指定もできるんだーとなったのでまとめて記載しています。 overlay_color The overlay color of the selected list item.. overlay_color is an ColorProperty and defaults to [0, 0, 0, 0.2]]. 選択状態のときの色指定ですね。overlayとあるので上塗りしているということ でしょうか。 progress_round_size Size of the spinner for switching of selected_mode mode. progress_round_size is an NumericProperty and defaults to dp(46). progress_round_color Color of the spinner for switching of selected_mode mode. progress_round_color is an NumericProperty and defaults to None. グルグルするものですね。どうやらサイズも変更できるみたいです。 get_selected(self) Returns True if at least one item in the list is checked. なにやら、選択状態かどうか調べられるメソッドがありそうですね。ただし、 少し試しただけではうまくいきませんでした。引数でなにがしかを指定する 必要があるようです。 get_selected_list_items(self) Returns a list of marked objects: [, …] こちらが使われていたもので、上と同じようなものになります。ただし、こちら は選択したオブジェクトをリストで返すようになっています。 unselected_all(self) selected_all(self) on_selected(self, *args) Called when a list item is selected. on_unselected(self, *args) Called when a list item is unselected. こちらも重要なものです。selected_allメソッドなんかは全選択する際に 使われそうですね。 まとめ はい、ということで今日はこれにて終わりたいと思います!早めに切り上げようかと 思ってましたが。。 さていかがだったでしょうか。保持しているアイテムの管理なんかはうってつけのウィ ジェットになるかと思われます。ちょっと自分のスマホなんかを見ると、Googleフォト なんかは同じSelectionコンポーネントではなかろうかと見込んでいます。 来週は、個人的には密かに待望のSnackbar篇となります。これを使えるとなるとまた アプリの幅が広がりそうですね。ということで今週はこの辺りで。 それでは、ごきげんよう。 参照 Components » Selection https://kivymd.readthedocs.io/en/latest/components/selection/ DeepL 翻訳ツール https://www.deepl.com/ja/translator
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python3】0から作るPython初心者プログラミング【01】-じゃんけんプログラム-

【初回ご挨拶】こんにちは! ぬかさんエンジニアリングです。(初投稿‼) この「0から作るPython初心者プログラミング」シリーズは、Python初心者である私が、初心者の初心者による初心者のための実践的プログラミングスキルを皆さんと実践的に学び共有していきたいという趣旨の元に発足した企画です。 お題となるプログラムを最初に提示しますので、各自コーディングをした後にこの記事を読みながら答え合わせをしてみてください! Python入門書を読み終えてこれから実践的コーディングをたくさんこなしていきたいと思っている........けどどんなプログラムを作ればいいかわからない‼とお題に困っていた皆さん、このシリーズをこなして実践力が上がりました!と言ってもらえるように頑張ってコツコツ書いていきますので是非ご一読を!それからLGTMも是非! $$$$ ▼以下要点(次回以降はここからスタート) 【趣旨】 Python初心者プログラマーが入門書で学んだ知識を実践的なコーディングを通じて身に着けていくためのお題を提供します。 お題を基に各自コーディングに挑戦していただいた後、この記事でコーディングの過程を答え合わせします。 【対象】 Pythonの入門書を読んで理解はしたけど何か目的をもって実践的にコーディングをしたい方。 ProgateでPythonコースをLv5まで勉強したけど応用力が身に着いていないと感じている方。 【初心者とは】 この記事シリーズでの初心者は下記の項目を理解済みであることが目安となっています。 [演算子, 標準ライブラリ, 条件分岐, 繰り返し処理, 例外処理, リスト, タプル, セット, 辞書, オブジェクト指向] 【利用ライブラリ & Python3 --version】 ・Google Colaboratory 以下のリンクからアクセスして使い方を確認した後、左上のファイルタブから「ノートブックを新規作成」を選択して自分のプログラムを作りましょう。ファイルはGoogleDriveに保存されるため、自分のGoogleアカウントと連携させるのを忘れないようにしましょう。 ・Python 3.7.12 $$$$ それではさっそく本題に入っていきましょう 第【01】回 -じゃんけんプログラム- このシリーズの最初のステップは、言わずと知れた初心者プログラム界の重鎮である-じゃんけんプログラム-です。 まさに基礎中の基礎とも言っていい処理が多数用いられるため、とりあえずじゃんけんができるようになれば立派な初心者ではないでしょうか。 ちなみに中、上級者って?中級者はライブラリやフレームワークを十分理解している方を想定しており、上級者は中級者までの技術を習得した上で商業サービスを一部始終開発できるプロを想定しています。 【お題】コンピュータとじゃんけんをして勝敗を判定するプログラムを作ろう! ------------------------------------------------------- じゃんけんの選択肢:{0: 'グー', 1: 'チョキ', 2: 'パー'} ------------------------------------------------------- あなたの出す手を入力してください(整数:0, 1, 2) > 1 コンピュータの手:パー あなたの手:チョキ <><><><><><><><><> 勝敗結果:勝ち <><><><><><><><><> 上記の出力が得られるプログラムを作成してください。 30行以内で作成してください。(空白行は含まない) ユーザー定義関数を利用せず ←コメントを受けて追加(次回からユーザー定義関数を利用) ≪お助けヒント≫ ヒント1 コンピュータの手にrandomモジュールを使います ヒント2 入力を受け取る際、Errorが発生しないように例外処理を設定する。 ヒント3 勝敗判定のアルゴリズムにbool値を用いて行数を削減する。 $$$$ 【解答】 解答は以下の通りです。 ※この解答はあくまで私の回答です。各々の方法でお題が解けていればそれで全然かまいません。むしろ、もっと簡潔な方法があればご教示頂けると助かります 0P【01】解答.py #じゃんけんの手の辞書を定義 d = {0:"グー",1:"チョキ",2:"パー"} my_hand_key = tuple(d.keys()) #出力 print("-"*55 + f"\nじゃんけんの選択肢:{d}\n" + "-"*55) #コンピュータの手アルゴリズム import random computer_hand = random.randint(0, 2) #入力(自分の手)アルゴリズム my_hand = 999 while my_hand not in my_hand_key: my_hand = input("あなたの出す手を入力してください(整数:0, 1, 2) > ") try: my_hand = int(my_hand) except: print("整数0, 1, 2を入力をして下さい") #勝敗判定アルゴリズム result = False if my_hand == computer_hand: result = "引き分け" else: if my_hand == 0 and computer_hand == 1: result = True elif my_hand == 1 and computer_hand == 2: result = True elif my_hand == 2 and computer_hand == 0: result = True if isinstance(result, bool): result = "勝ち" if result else "負け" #出力 print(f"コンピュータの手:{d[computer_hand]}") print(f"あなたの手:{d[my_hand]}") print("<>"* 6 + f"\n勝敗結果:{result}\n" + "<>"* 6) ##出力結果 ------------------------------------------------------- じゃんけんの選択肢:{0: 'グー', 1: 'チョキ', 2: 'パー'} ----------------------------------------------------- あなたの出す手を入力してください(整数:0, 1, 2) > 1 コンピュータの手:パー あなたの手:チョキ <><><><><><><><><> 勝敗結果:勝ち <><><><><><><><><> 【解説】 〔プログラムの組み立て方〕 いきなりプログラムを作って下さいと言われても何から始めればいいか分からなかった方もいるのではないでしょうか。そんな方に私なりのプログラムの組み立て方をご紹介します。(私の成長によって書き換えあり) ①まず、期待されている出力の固定部分(文字列など)をPrint()で作成する。そうすると自ずと可変部分がいくつあるか分かるので、可変部分を適当な変数で仮に定義する。(折りたたみを開くと例を確認できます) #出力 d = {} computer_hand = [] my_hand = [] result = [] print("-"*55) print(f"じゃんけんの選択肢:{d}") print("-"*55) print(f"コンピュータの手:{computer_hand}") print(f"あなたの手:{my_hand}") print("<>"* 6) print(f"勝敗結果:{result}") print("<>"* 6) ②可変部分からそれぞれに期待されている機能を推測し、コメント機能で大まかなブロック分けを行う。(折りたたみを開くと例を確認できます) #じゃんけんの選択肢を辞書で定義 d ={} #出力 print("-"*55) print(f"じゃんけんの選択肢:{d}") print("-"*55) #コンピュータの手アルゴリズム computer_hand = [] #入力(自分の手)アルゴリズム my_hand = [] #勝敗判定アルゴリズム result = [] #出力 print(f"コンピュータの手:{computer_hand}") print(f"あなたの手:{my_hand}") print("<>"* 6) print(f"勝敗結果:{result}") print("<>"* 6) ③ここまでブロック分けをしたらあとはそれぞれの機能を実現するために持っている知識を総動員します。(折りたたみを開くと例を確認できます) #じゃんけんの選択肢を辞書で定義 #定義した辞書は中身を変更しないから…… <<<<<< d ={} #出力 print("-"*55) print(f"じゃんけんの選択肢:{d}") print("-"*55) #コンピュータの手アルゴリズム #コンピュータの手はランダムにしたいから…… <<<<<< computer_hand = [] #入力(自分の手)アルゴリズム #自分の手を入力したいから…… <<<<<< my_hand = [] #勝敗判定アルゴリズム ##勝ち負けの場合分けをしたいから…… <<<<<< result = [] #出力 print(f"コンピュータの手:{computer_hand}") print(f"あなたの手:{my_hand}") print("<>"* 6) print(f"勝敗結果:{result}") print("<>"* 6) この3ステップができれば学んだ知識を迷わず使えるでしょう。 〔各機能の作り方〕 ①じゃんけんの選択肢を辞書で定義 d = {0:"グー",1:"チョキ",2:"パー"} my_hand_key = tuple(d.keys()) 選択肢の定義は辞書のキーをタプルに変換することで不要な変更を防いで完成します。 まずは期待される出力にあるじゃんけんの手の辞書を作成します。そして、じゃんけんの手はこのプログラムの中で書き換える必要が無いので辞書をタプルに変換して予想外の変更を防ぎます。 タプルを使うメリットは、詳しく書かれている記事を見つけたので以下のリンクからアクセスして見てみてください。 ②コンピュータの手アルゴリズム import random computer_hand = random.randint(0, 2) コンピュータの手は、randomモジュールのrandom.randint(0, 2)を利用して0~2までの整数のランダム生成で完成します。 ③入力(自分の手)アルゴリズム my_hand = 999 while my_hand not in my_hand_key: my_hand = input("あなたの出す手を入力してください(整数:0, 1, 2) > ") try: my_hand = int(my_hand) except: print("整数0, 1, 2を入力をして下さい") 自分の手アルゴリズムは、自分の手の入力機能、正しい入力を受け取るまで処理を繰り返す機能、例外的な入力を処理する機能の3ステップで完成します。 まず、自分の手を入力する機能をinputで作ります。プログラムは実行中は変更不可なので自分の手を選ぶにはinputを使うのが一般的です。 次に、期待する整数0, 1, 2を受け取るまで処理を繰り返すためにwhile文を使います。 while文の代表的な使い方は以下の通りです。 #1.基本 ##条件式がTrueである間は処理を繰り返す。 while 条件式: 処理 #2.breakの使い方 ##条件式①がTrueである間は処理を繰り返し、条件式②に当てはまった場合に処理を終了する。 while 条件式①: 処理 if 条件式②: break #3.continueの使い方 ##処理を繰り返し、条件式②に当てはまる場合のみ処理をスキップして次の処理に移る。 while 条件式①: 処理 if 条件式②: continue #4.elseの使い方 ##条件式①がTrueである間は処理①を繰り返し、条件式②に当てはまった場合には処理①を終え処理②を行って終了する。 while 条件式①: 処理 if 条件式②: break else: 処理② #5.Trueの使い方 ##処理をTrue扱いで繰り返し、条件式に当てはまった場合に処理を終了する。 while True: 処理 if 条件式: break 今回は基本形を用いて実装します。 条件式として「①で作成したタプルの中に入力した値が無ければ処理を続ける」を設定し、その条件に当てはまらなかった場合には入力をint型に変換してmy_handを更新します。ただし、条件式の中に未定義の変数は使えないのでmy_hand = 999で初期化しています。 最後に、入力がint型に変換できなかった場合に例外処理を行います。かみ砕くと、文字列が入力されたら例外的に処理を加えようということです。 例外処理の基本の使い方は以下の通りです。 #1.基本 try: 例外(Error)が発生する可能性がある処理 except: 例外(Eroor)を受けて実行する処理 文字列をint型に変換しようとしたらErrorが発生し、「整数0, 1, 2を入力をして下さい」と出力する例外処理を行います。 以上3ステップによって0, 1, 2のどれかのint型の値を必ず受け取ることができるようになります。 ④勝敗判定アルゴリズム result = False if my_hand == computer_hand: result = "引き分け" else: if my_hand == 0 and computer_hand == 1: result = True elif my_hand == 1 and computer_hand == 2: result = True elif my_hand == 2 and computer_hand == 0: result = True if isinstance(result, bool): result = "勝ち" if result else "負け" 勝敗判定は、if文を使ってコンピュータの手と自分の手を比較し、勝敗の場合分けを行うことで完成します。 まず、行数の制限を考えず一番基本的な形で書いてみましょう。コードは以下の通りです。 result = "" if my_hand == 0: #グー if computer_hand == 0: #グー result ="引き分け" elif computer_hand == 1: #チョキ result ="勝ち" elif computer_hand == 2: #パー result ="負け" elif my_hand == 1: #チョキ if computer_hand == 0: #グー result ="負け" elif computer_hand == 1: #チョキ result ="引き分け" elif computer_hand == 2: #パー result ="勝ち" elif my_hand == 2: #パー if computer_hand == 0: #グー result ="勝ち" elif computer_hand == 1: #チョキ result ="負け" elif computer_hand == 2: #パー result ="引き分け" 行数に制限が無ければ正直このコードでも構わないのですが、今回はより簡潔になるコードに変換していきます。 そのために用いるのがbool値です。 勝ちの場合にはTrue、Falseの場合には負けという判定をすることで負けのコード数を省略できます。 その準備として結果出力用の変数resultにFalseを代入して初期化します。 result = False 次に引き分けについて考えます。 引き分けになる条件はコンピュータの手と自分の手が同じであることなので、コードに直すと以下のようになります。 if my_hand == computer_hand: result = "引き分け" 省略できましたね。 ここからは勝ちと負けについて考えます。 勝ちは通常通りにコードを書きますが、 resultにはTrueを代入します。詳細は以下の通りになります。 if my_hand == 0 and computer_hand == 1: result = True elif my_hand == 1 and computer_hand == 2: result = True elif my_hand == 2 and computer_hand == 0: result = True 最後に、resultがTrueの場合は「勝ち」を代入し、そうでなければ「負け」を代入します。 このように記述することによって「負け」についてコード数を省略することができましたね。 ちなみにisinstance(要素, 型)は要素が指定した型と同じ型かどうかbool値で返してくれるもので、引き分けの際に処理されないようにしています。 if isinstance(result, bool): result = "勝ち" if result else "負け" ちなみに、このif文が普段と書き方が異なっていて戸惑った方もいるのではないでしょうか。実は、これはif文を「三項演算子」を使って記述しています。if文の三項演算子の使い方は以下の通りになります。 #if...else...の三項演算子 Trueの場合の処理 if 条件式 else Falseの場合の処理 #if...elif...else...の三項演算子 条件式1がTrueの場合の処理 if 条件式1 else 条件式1がFalseの場合の処理 if 条件式2 else 条件式2がFalseの場合の処理 ここまでの処理を簡潔にまとめると以下のようになります。 result = False if 引き分けの条件: result = "引き分け" else: if 勝ちの条件1: result = True elif 勝ちの条件2: result = True elif 勝ちの条件3: result = True if 引き分けではないという条件: result = "勝ち" if resultがTrueという条件 else "負け" ここまでくれば、この勝敗判定アルゴリズムが理解できたのではないでしょうか。 ⑤出力 print(f"コンピュータの手:{d[computer_hand]}") print(f"あなたの手:{d[my_hand]}") ②と③で受け取ったじゃんけんの手の値を0, 1, 2の数値ではなく、グー, チョキ, パーに変換することで出力は完成します。 これは、辞書の検索方法を使います。つまり、辞書[キー]によって要素を検索するということです。 以上がこのじゃんけんプログラムの解説になります。 長くなりましたが皆様お疲れさまでした 【終わりに】 今回は初回と言うことで基礎の基礎となるじゃんけんプログラムの作り方を作っていきましたが、いかがだったでしょうか。 少しでも実践力に繋がったと感じて頂けたなら本望です。 もしもコーディングの部分で間違いなどありましたら編集リクエストからご指摘いただけると幸いです。 また、その他質問などございましたらコメントをお願い致します。 次回はじゃんけんプログラムの応用である「あっち向いてほいプログラム」を予定しております。 この記事が良かったと感じたらLGTMを宜しくお願いします!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ubuntu 20.04でpython3をデフォルトに設定

久しぶりにUbuntu 20.04をインストールしたら、Python3をデフォルトにする方法を忘れていたのでメモ。 結論としては以下の実行。 $ sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.8 0 これだけでpython3がデフォルトになる。 $ python --version Python 3.8.10 自分の環境では何故かpython2が入っていなかった(20.04って元々そうでしたっけ?)。 【以下はただの参考情報】 変更するものがないのでupdate-alternativesで--configすると「変更もなにも変更対象のものがない」と言われ、プライオリティをつけずに--installすると「 」と最後にプライオリティのための番号が必要だよと言われた(ので今回は0をつけた)。 $ which python $ which python3 /usr/bin/python3 $ sudo update-alternatives --config python update-alternatives: error: no alternatives for python $ sudo update-alternatives --install /usr/bin/python python /usr/bin/python3.8 update-alternatives: --install needs <link> <name> <path> <priority>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[matplotlib]任意の数の色を使って色分けする

※ この記事を書く際に利用したコードに関連するライブラリのバージョンは以下になります. Python: 3.9.7 matplotlib: 3.4.2 numpy: 1.20.3 seaborn: 0.11.1 要点だけまとめ 色分けで使いたい色の数に応じた対応: 3~5色程度で色分けしたい: 手動でラベルから色に対応する配列を作る. ~20色: matplotlib.tab10やmatplotlib.tab20などを使う. 20色以上: matplotlib.colors.CSS4_COLORSを使う. クラスタやカテゴリごとに色分けしたい 使う場面 以下のように,散布図の点たちをクラスタごとに(もしくは,クラスタに限らず,何らかの条件で)色分けしたいようなケースを考えます. クラスタ数が3など小さい場合は,label2color = ['r', 'g', 'b']のように設定して,以下のような関数を使えばよいです. クラスタごとに点を色分けしてプロットする def plot_points(d, label2color): fig, ax = plt.subplots(figsize=(8, 8)) for i in range(len(d)): # d[i]: クラスタiに属する点[x,y]のリスト ax.scatter(d[i][:, 0], d[i][:, 1], s=6, c=label2color[i], label=i) # ここの引数cで色を設定している ax.set_xlabel('x') ax.set_ylabel('y') ax.legend(fontsize=12, prop={'size':24}, loc='center left', bbox_to_anchor=(1,0.5), markerscale=10) plt.show() しかし,クラスタ数が多くなってくると,手動でlabel2colorのような配列を設定するのは骨が折れます. この記事で説明すること この記事では,任意の数の色で色分けする方法について説明します. 結論を述べると,10色~20色ほど使いたい場合,matplotlib.cm.tab10やmatplotlib.cm.tab20などのカラーマップが用意されているのでそれを使えばいいです. また,それ以上の数の異なる色を使いたい場合は,matplotlib.colors.CSS4_COLORSを使うと良いかと思います. ~20色程度の色を使いたい場合 この場合は,matplotlib.cm.tab10やmatplotlib.cm.tab20を使うとよいです. 例えば,上で示したコード中のax.scatter()において,引数c=matplotlib.cm.tab20(i) (iはクラスタの番号)のように設定します. すると,さきほど手動で3色分定義していた,label2colorのような配列を定義しなくても自動で色分けしてくれます. tab20を使って色分けしてプロットする def plot_points_tab(d): fig, ax = plt.subplots(figsize=(8, 8)) for i in range(len(d)): ax.scatter(d[i][:, 0], d[i][:, 1], s=6, c=matplotlib.cm.tab20(i), label=i) ax.set_xlabel('x') ax.set_ylabel('y') ax.legend(fontsize=12, prop={'size':24}, loc='center left', bbox_to_anchor=(1,0.5), markerscale=10) plt.show() クラスタ数=20として点列を生成して,上の関数を利用してプロットすると以下のようになります. 20個のクラスタが異なる色で色分けされていることがわかります(結構似ている色もありますが). 20色以上程度の色を使いたい場合 先ほど使っていたmatplotlib.cm.tab20は20色しか用意されていないので,それ以上の数の色を使いたい場合は違う方法を取らないといけません. matplotlib.colors.CSS4_COLORSについて そこで,今回は matplotlib.colors.CSS4_COLORS を使う方法を紹介します. matplotlib.colors.CSS4_COLORSでは148色の色が定義されています. matplotlib.colors.CSS4_COLORSについて確認 print(type(matplotlib.colors.CSS4_COLORS)) # >> <class 'dict'> print(len(matplotlib.colors.CSS4_COLORS)) # >> 148 つまり,matplotlib.colors.CSS4_COLORSは辞書型で148個の要素からなることがわかります. 実際の中身は,以下のように,キー = 利用できる色名,値 = 対応するカラーコード として格納されています. {'aliceblue': '#F0F8FF', 'antiquewhite': '#FAEBD7', 'aqua': '#00FFFF', 'aquamarine': '#7FFFD4', 'azure': '#F0FFFF', 'beige': '#F5F5DC', 'bisque': '#FFE4C4', 'black': '#000000', ... ランダムに任意の数のカラーコードを取得してリストにする 今回は,必要な数だけカラーコードを取得するために,この辞書からランダムに抽出を行います. それを行う関数を以下に示します. 任意の数のカラーコードを生成する関数 def choose_colors(num_colors): # matplotlib.colors.CSS4_COLORSの値だけをリストにする tmp = list(matplotlib.colors.CSS4_COLORS.values()) # リストにしたものをランダムにシャッフルする random.shuffle(tmp) # 必要な数だけ先頭から取り出してreturnする label2color = tmp[:num_colors] return label2color この関数 choose_colors() を使えば,自動で各ラベルに対応する色のリストを作ることができます. つまり,冒頭で示したような,ラベルと色の対応を表すリストlabel2colorが,任意のサイズで作れることになります. 実際に,この関数 choose_colors() と冒頭のプロット用の関数 plot_points() を使って,クラスタ数=30でプロットしてみると以下のようになりました. ほとんど見分けがつかないが微妙に違う色(7番と10番のほとんど同じピンクなど)がありますが,この辺を解決するのは難しそう... ちなみに148色以上使いたい場合(そんなことなかなかなさそうですが)は,matplotlib.colors.XKCD_COLORSというものがあり,こちらは949色使えるそうです. 参考 matplotlibで色をたくさん使う
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】Qiita デイリー LGTM 数ランキング【自動更新】

他のタグ AWS Android Docker Git Go iOS Java JavaScript Linux Node.js PHP Python Rails React Ruby Swift TypeScript Vim Vue.js 初心者 集計について 期間: 2021-10-16 ~ 2021-10-17 GitHub スターをもらえるととっても励みになります LGTM 数ランキング 1 位: AtCoderで入緑するために必要だったアルゴリズムとデータ構造 (2021年10月版) Python アルゴリズム AtCoder 競技プログラミング AtCoderBeginnerContest 6 LGTM 2 ストック @malleroid さん ( 2021-10-16 18:52 に投稿 ) 2 位: Pytorch Template 個人的ベストプラクティス(解説付き) Python データ分析 深層学習 PyTorch 4 LGTM 5 ストック @takubb さん ( 2021-10-17 10:35 に投稿 ) 3 位: [matplotlib]任意の数の色を使って色分けする Python 初心者 matplotlib 1 LGTM 1 ストック @y629 さん ( 2021-10-16 16:22 に投稿 ) 4 位: オムロン環境センサ(2JCIE-BU)をラズパイで使ってみた。(3) Python PostgreSQL RaspberryPi psycopg2 2JCIE-BU 1 LGTM 0 ストック @Toshiaki0315 さん ( 2021-10-17 09:03 に投稿 )
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

メルカリの検索結果からタイトルと値段をスクレイピングしたかった

前回までのあらすじ 前回の記事では、とりあえずアクセスしてページ内容を表示するものだった。 せっかくなので、取れそうな情報を抜き出してみた。 取りたい情報 検索結果として表示されたページの商品名 上記商品名に対応する値段 取得手順 スタートページにヘッドレスモードでアクセス ちょっと待ってからページ内にある商品名と値段を取得、画面出力 「次へ」ボタンを探してクリック、同様に取得/出力しながらループ。 クリックできなければループを抜けて終了 ソースコード mercari.py # メルカリ上で動的レンダリングされた商品情報を取得し、すべてのページから商品名、価格、タイトルを取得する。 from selenium import webdriver from time import sleep from selenium.common.exceptions import * options = webdriver.ChromeOptions() options.add_argument('--headless') options.add_argument("--window-size=1920,1080") options.add_argument("--disable-gpu") options.add_argument( "user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36") browser = webdriver.Chrome('chromedriver.exe',options=options) # mercari:指定条件を検索したURLにアクセス url = 'https://jp.mercari.com/search?status=on_sale&page=1&t1_category_id=5&category_id=5' browser.get(url) sleep(3) # カウンタ(表示用) no = 0 # 外ループ:メルカリの次へボタンが無くなるまで。 while True : sellItems = browser.find_elements_by_tag_name("mer-item-thumbnail") # 内ループ:ページ内のアイテム情報を取得しきるまで。 for item in sellItems : no += 1 name = item.get_attribute("item-name") price = item.get_attribute("price") print(str(no) + ' : ' + name + ' : \\' + price) # 「次へ」ボタンを探して、見つかればクリック try: # 自動でページ遷移すると画面読み込み時の初期処理に割り込まれてボタン押下が出来ないので、execute_scriptで対策する。 buttonClick = browser.find_element_by_xpath("//mer-button[@data-testid='pagination-next-button']") browser.execute_script("arguments[0].click();",buttonClick) sleep(3) # 「次へ」ボタンが無ければループを抜ける except NoSuchElementException: break # 終了処理(ヘッドレスブラウザを閉じる) browser.quit() 実行結果 実行結果 No(数字) : 商品名 : \価格 もうちょっと発展させてCSVに出力したり、スタートページを別ファイル読み込みにしたりと、 やれることはまだありそう。 楽しくなってきたので気が向いたらまた更新します。よろしくね。 参考 【Python】Selenium:ElementClickInterceptedExceptionエラーの原因と解決方法 button.click()が単純にできなかったので、エラーメッセージに出てきたExceptionググったら execute_script()を使う方法があったので使わせてもらいました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pythonで空のリストをデフォルト引数にしようと def func(l=list()) と書いてはいけない

関数書くときに 引数を受け取らなかった → 結果をlistにして返す 引数にlistを受け取った → 続きに書き足して返す みたいな動作を書きたいことがあると思います 失敗した書き方 そこで、以下のように書いてみました 上手くいっているように見える例1 def func1(n, l=list()): for k in range(n): l.append(k) return l func1(3) # [0, 1, 2] が返ってきます 上手くいっているように見える例2 def func1(n, l=list()): for k in range(n): l.append(k) return l l1 = func1(3) l2 = func1(3, l1) l2 # [0, 1, 2, 0, 1, 2] が返ってきます どうやら期待通り動いてんね、という事で以下を実行するとおかしなことになります 失敗が分かる例 def func1(n, l=list()): for k in range(n): l.append(k) return l l1 = func1(3) l2 = func1(3, l1) # l2は [0, 1, 2, 0, 1, 2] になっている l3 = func1(2) l4 = func1(2, l3) # l4は [0, 1, 0, 1] になっている筈が… l4 # [0, 1, 2, 0, 1, 2, 0, 1, 0, 1] が返ってきます …どうやら何か失敗しているようです 動作を確認する 上記のl1~l4のオブジェクトIDを確認してみます IDを確認 >>> print(id(l1), id(l2), id(l3), id(l4)) 2093705104064 2093705104064 2093705104064 2093705104064 引数を受け取らなかった場合は新しく空のlistを作ってそこに書き足していくという動作を期待していたので l1~l2が同じオブジェクト l3~l4が同じオブジェクト l1~l2とl3~l4は別のオブジェクト というのを期待していたんですが全部同じIDになってます。これが意図しない動作の原因のようです。 考察 IDを見て考えた推測ですが、1行目の「def func1(n, l=list()):」が原因ではないかと思います。list()により作成されたlistオブジェクトが関数情報を保管するスコープに置かれていて、引数を省略したらその作成済みlistオブジェクト(上の例だとIDが2093705104064になっているlistオブジェクト)を引数として受け取るという事ではないでしょうか。インタプリタが関数をパースするときにlist()を普通に実行して格納しちゃってる感じかな?と思ってます。 対策 というわけでNoneのように判別がやりやすいやつをデフォルトに入れておいて、Noneだったら新しいlistを作るという書き方に変えればやりたかった動作が実現できます。 対策例 def func2(n, l=None): if l is None: l = list() for k in range(n): l.append(k) return l l1 = func2(3) l2 = func2(3, l1) l3 = func2(2) l4 = func2(2, l3) print(l4) print(id(l1), id(l2), id(l3), id(l4)) 関数が上から下に順番に実行されるものと考えているとハマりやすい罠ではないかと思います。ご注意ください。 試行環境 Windows10 + miniconda python 3.8.8
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pip3を使う場合のコマンドメモ

前提 pip3を使う場合、よくネット上にあるコマンドとして、 「pip3 install ~~~」 みたいなコマンドを指定すればいい!みたいなことが書かれていますよね? でもこれらのほとんどが利用できません。 そこで色々調べてみたら、下記のコマンドで動きました。 pip3が動いたコマンド ターミナル sudo -H pip3 install 〜〜〜〜 これです。 sudo と ーH が関係していると思います。 何やら、-Hは別ユーザーとして、そしてsudoでは管理者権限で、pipを利用するみたいです。 詳しいことがわかっていなくてすみません。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pipでインストールしたものが「command not found」になるときの対処法

前置き pipで何かライブラリ等をインストールして、使用しようとしたら、「command not found」になることが過去に多々ありました。 最近はPythonを使っていなかったのですが、社会人になってしばらくしてまたPythonをやりたくなってジュピターノートブックをpipでインストールした際に、 「command not found」で動かないという事象が出ました。 今回はこれに対する簡単な対処法です。 パスを確認する ターミナル command not found: jupyter こうなった時は、まずはライブラリのパスを確認します。 ターミナル pip3 show jupyter すると、このように表示されます。 ターミナル Name: jupyter Version: 1.0.0 Summary: Jupyter metapackage. Install all the Jupyter components in one go. Home-page: http://jupyter.org Author: Jupyter Development Team Author-email: jupyter@googlegroups.org License: BSD Location: /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages Requires: ipykernel, ipywidgets, jupyter-console, nbconvert, notebook, qtconsole Required-by: bashの設定ファイルにパスを通す この中の、 Location: /Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages の部分に、ライブラリ(今回はjupyter)がインストールされています。 なので、このパスをbashの設定ファイルに追記してやります。 ターミナル export PATH=/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages:$PATH 上記のコマンドでは、bashの設定ファイルに追記をしています。 そして、追記が終わったら、下記のコマンドを打ちます。 ターミナル source ~/.bash_profile こちらでは、export~で追記した内容を設定ファイルに反映させています。 これで、作業は終了です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

金属部品の品質不良を検出するアプリを作ってみた

#1.はじめに# 私は金属部品メーカーで勤務しています。部品の製造工程における品質検査項目の中には定量化が難しいものがあり、感応検査に頼らざるを得ない状況があります。こういった項目の検査を人の手に頼らず行えるようにする手段として機械学習による合否判定を試してみたいと考え、金属部品の画像をアップロードすると品質不良の有無を判定するアプリを作成してみました。 #2.開発環境# ・VAIO TYPE Z (VJZ131) ・WINDOWS 10 HOME EDITION ・Google Colaborabory ・Python(Ver 3.8.5) #3.使用したライブラリ# ・TensorFlow Googleが開発した機械学習のためのライブラリ。 ・OpenCV Open Source Computer Vision Libraryの略で画像処理・画像解析に使用するライブラリ。 ・Numpy Pythonで数値計算を行うためのライブラリ。 ・Flask PythonでWebアプリケーションを作成するためのライブラリ #4.学習データ# Kaggleで公開されているポンプ用金属部品(インペラ)の画像データセットを使用。 "casting product image data for quality inspection" https://www.kaggle.com/ravirajsinh45/real-life-industrial-dataset-of-casting-product #5.学習モデルの構築# ①ライブラリのインポート~画像データの読み込み defect_recognition.py # ライブラリのインポート import os import cv2 import numpy as np import matplotlib.pyplot as plt from tensorflow.keras.utils import to_categorical from tensorflow.keras.layers import Dense, Dropout, Flatten, Input from tensorflow.keras.applications.vgg16 import VGG16 from tensorflow.keras.models import Model, Sequential from tensorflow.keras import optimizers import glob # ディレクトリの変更 os.chdir(os.path.dirname(os.path.abspath(__file__))) # ファイルパスの設定 path_OK = os.listdir('./OK') path_DEFECT = os.listdir('./DEFECT') path_JUDGE = os.listdir('./JUDGE') # データを合格、不合格、検証用に分類 img_OK = [] img_DEFECT = [] img_JUDGE=[] for i in range(len(path_OK)): img = cv2.imread('./OK/' + path_OK[i]) img = cv2.resize(img, (200,200)) img_OK.append(img) for i in range(len(path_DEFECT)): img = cv2.imread('./DEFECT/' + path_DEFECT[i]) img = cv2.resize(img, (200,200)) img_DEFECT.append(img) # 検証用データ for i in range(len(path_JUDGE)): img = cv2.imread('./JUDGE/' + path_JUDGE[i]) img = cv2.resize(img, (200,200)) img_JUDGE.append(img) X = np.array(img_OK + img_DEFECT) y = np.array([0]*len(img_OK) + [1]*len(img_DEFECT)) ②画像データのシャッフル rand_index = np.random.permutation(np.arange(len(X))) X = X[rand_index] y = y[rand_index] # データの分割 X_train = X[:int(len(X)*0.8)] y_train = y[:int(len(y)*0.8)] X_test = X[int(len(X)*0.8):] y_test = y[int(len(y)*0.8):] # categorical_crossentropyとともに用いるためのバイナリのクラス行列に変換 y_train = to_categorical(y_train) y_test = to_categorical(y_test) ③モデルの構築 今回はVGG16という学習済みのモデルを使って、品質不良の有無を判別するためのモデル構築(転移学習)を行っていきます。VGGモデルはオックスフォード大学のVGG(Visual Geometry Group)チームが開発を行い、「ImageNet」という120万枚の画像で構成される巨大なデータセットで学習を行った画像分類モデルで、2014年に行われた画像認識のコンペティションで2位と優秀な成績を収めています。VGGにはVGG16とVGG19の2種類のモデルがあり、今回使用するVGG16は畳み込み13層、全結合層3層の合計16層で構成されるニューラルネットワークです。 # モデルにvggを使用 input_tensor = Input(shape=(200, 200, 3)) vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor) # vggのoutputを受け取り、2クラス分類する層を定義します top_model = Sequential() top_model.add(Flatten(input_shape=vgg16.output_shape[1:])) top_model.add(Dense(256, activation='relu')) top_model.add(Dropout(0.5)) top_model.add(Dense(2, activation='softmax')) # vggと、top_modelを連結 model = Model(inputs=vgg16.input, outputs=top_model(vgg16.output)) # vggの層の重みを変更不能にします for layer in model.layers[:19]: layer.trainable = False # コンパイルします model.compile(loss='categorical_crossentropy', optimizer=optimizers.SGD(lr=1e-4, momentum=0.9), metrics=['accuracy']) ④学習を行う # 学習を行います model.fit(X_train, y_train, batch_size=16, epochs=15, validation_data=(X_test, y_test)) # 重みを保存 result_dir = 'results' if not os.path.exists(result_dir): os.mkdir(result_dir) model.save(os.path.join(result_dir, 'model.h5')) 以下は学習の過程です。 ⑤合否判定の関数とモデルの評価 # 画像を一枚受け取り、合格か不合格かを判定する関数 def pred_quality(img): img = cv2.resize(img, (200, 200)) pred = np.argmax(model.predict(np.array([img]))) if pred == 0: return 'OK' else: return 'DEFECT' # 精度の評価 scores = model.evaluate(X_test, y_test, verbose=1) print('Test loss:', scores[0]) print('Test accuracy:', scores[1]) ⑥検証 # 検証用データ10枚でテストを行う import os import glob files_list=[] path = "/content/drive/My Drive/Defect_recognition/JUDGE" files = glob.glob(path + "/*") for f in files: files_list.append(os.path.basename(f)) count=0 for i in img_JUDGE: cv2_imshow(i) if count==0: print("ファイル名:" + files_list[0]) else: print("ファイル名:" + files_list[count]) count+=1 print("判定結果:" + pred_quality(i)) ファイル名:検証データ_不良品_0_9980.jpeg 判定結果:DEFECT ファイル名:検証データ_不良品_0_9963.jpeg 判定結果:DEFECT ファイル名:検証データ_不良品_0_9877.jpeg 判定結果:DEFECT ファイル名:検証データ_不良品_0_9879.jpeg 判定結果:DEFECT ファイル名:検証データ_不良品_0_9995.jpeg 判定結果:DEFECT ファイル名:検証データ_良品_0_9990.jpeg 判定結果:OK ファイル名:検証データ_良品0_9843.jpeg 判定結果:OK ファイル名:検証データ_良品0_9959.jpeg 判定結果:OK ファイル名:検証データ_良品_0_9966.jpeg 判定結果:OK ファイル名:検証データ_良品_0_9850.jpeg 判定結果:OK #6.Herokuへのデプロイ# 5で作成したモデルを使ってWEBアプリを作成していきます。 PYTHONコード main.py import os from flask import Flask, request, redirect, render_template, flash from werkzeug.utils import secure_filename from tensorflow.keras.models import Sequential, load_model from tensorflow.keras.preprocessing import image import numpy as np os.chdir(os.path.dirname(os.path.abspath(__file__))) classes = ["OK","DEFECT"] image_size = 200 UPLOAD_FOLDER = "uploads" ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg', 'gif']) app = Flask(__name__) def allowed_file(filename): return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS model = load_model('./model.h5')#学習済みモデルをロード @app.route('/', methods=['GET', 'POST']) def upload_file(): if request.method == 'POST': if 'file' not in request.files: flash('ファイルがありません') return redirect(request.url) file = request.files['file'] if file.filename == '': flash('ファイルがありません') return redirect(request.url) if file and allowed_file(file.filename): filename = secure_filename(file.filename) file.save(os.path.join(UPLOAD_FOLDER, filename)) filepath = os.path.join(UPLOAD_FOLDER, filename) #受け取った画像を読み込み、np形式に変換 img = image.load_img(filepath,target_size=(image_size,image_size)) # img = image.load_img(filepath, grayscale=True, target_size=(image_size,image_size)) img = image.img_to_array(img) data = np.array([img]) #変換したデータをモデルに渡して予測する result = model.predict(data)[0] predicted = result.argmax() pred_answer = "これは " + classes[predicted] + " です" return render_template("index.html",answer=pred_answer) return render_template("index.html",answer="") if __name__ == "__main__": port = int(os.environ.get('PORT', 8080)) app.run(host ='0.0.0.0',port = port) HTMLコード index.html <!DOCTYPE html> <html lang='ja'> <head> <meta charset='UTF-8'> <meta name='viewport' content="device-width, initial-scale=1.0"> <meta http-equiv='X-UA-Compatible' content="ie=edge"> <title>Quality Defect Checker</title> <link rel='stylesheet' href="./static/stylesheet.css"> </head> <body> <header> <img class='header_img' src="https://aidemyexstorage.blob.core.windows.net/aidemycontents/1621500180546399.png" alt="Aidemy"> <a class='header-logo' href="#">Quality Defect Checker</a> </header> <div class='main'> <h2> AIが送信された画像の合否を判定します</h2> <p>画像を送信してください</p> <form method='POST' enctype="multipart/form-data"> <input class='file_choose' type="file" name="file"> <input class='btn' value="submit!" type="submit"> </form> <div class='answer'>{{answer}}</div> </div> <footer> <img class='footer_img' src="https://aidemyexstorage.blob.core.windows.net/aidemycontents/1621500180546399.png" alt="Aidemy"> <small>&copy; 2019 Aidemy, inc.</small> </footer> </body> </html> ターミナルへ以下のコマンドを入力してHerokuへデプロイします。 #アプリのあるディレクトリへ移動 cd #ファイルパス #Herokuへログイン heroku login #Herokuでアプリを作成し、buildpackをpythonとする heroku create #アプリ名 --buildpack heroku/python $ git init $ heroku git:remote -a (アプリ名) $ git add . $ git commit -m '(更新内容を書く)' $ git push heroku master Herokuへのデプロイ完了が完了しました。モデル構築後に行った検証と同じ画像10点を使ってテストを行ったところ、すべて正しく判定されることが確認できました。 https://aidemy1023-3.herokuapp.com/ #7.まとめ# 今回モデルを最適化する過程で、厄介だったのは光の加減やピント等のバラツキでした。今回は画像サイズを大きくすることでこの問題は解消できましたが、ワークの映り方のばらつきは今回の取り組みを実際の品質検査に応用する際にも課題になり得るのではと考えています。実際の品質検査へ応用する際には今回実践した内容に加えて以下のようなアプローチも検討し、精度を向上させたいと考えています。 ・学習モデルをVGG16から変更する(Inception V3等) ・誤判定される画像に類似した特徴(光の当たり、ピントの具合等)を持つデータを水増して学習を行う #8.参考文献# 今回使用したデータセット https://www.kaggle.com/ravirajsinh45/real-life-industrial-dataset-of-casting-product VGG16の概要 https://jp.mathworks.com/help/deeplearning/ref/vgg16.html https://towardsdatascience.com/step-by-step-vgg16-implementation-in-keras-for-beginners-a833c686ae6c
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

poetry+pyenv-winの環境構築の備忘録

この記事is何 poetry_pyenv-winの導入の備忘録。 poetryについて(途中) tensorflow-gpuの導入まで(途中) 自分のPC環境と経緯 windows 10 pro/pyenv/portryで構築 以前はanacondaを使用していたが、pipでしかインストールできない最先端のライブラリが多すぎてanacondaに限界を感じたため、poetryに移行することにした。 pyenv-win,poetryの導入 pyenv-winのインストール↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ git clone https://github.com/pyenv-win/pyenv-win.git ~/.pyenv_win PATHを先頭に追加 C:\Users\ほげ\.pyenv_win\pyenv-win\bin C:\Users\ほげ\.pyenv_win\pyenv-win\shims この時点でshimsは存在しないが、これも通していいらしく、これを通さないと pyenv versions が認識されない pyenv install -l で使いたいpythonのバージョンを確認し pyenv install 3.8.0 などと指定しpythonをインストール、tensorflow-gpuを使用したかったのでcolabの3.7.12と近づけて新しめの3.8.0を持ってきた pyenv global 3.8.0 で全体にデフォルトで3.8.0を使うように設定。 poetry↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ (Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -UseBasicParsing).Content | python この方法だとpoetryが1.2.0以上には新しくならないらしい。 バージョンを確認 poetry --version > 仮想環境をプロジェクトのディレクトリ直下に作成するために、以下のコマンドを実行しておく これはちょっとよくわかってないが、おそらくデフォルトで作られるプロジェクトの位置が何かの変数で定められていてそれを変更するものだと思われる。 poetry config virtualenvs.in-project true プロジェクト作成からパッケージインストールの流れ anacondaに慣れていたので、若干戸惑った。以下の通り。 1.プロジェクトディレクトリに入る 2.仮想環境(shell)を起動 3.パッケージを追加・削除・スクリプトを実行など、anacondaでactivateした後のことがすべてできる。変更はpyproject.tomlに記載する/直接コマンドをたたく/poetry.lockに手を加えるなどの方法で行う。 poetry new projectname で新しいプロジェクトを作成。↓のやつが作られる。 poetry-demo ├── pyproject.toml ├── README.rst ├── poetry_demo │ └── __init__.py └── tests ├── __init__.py └── test_poetry_demo.py pyproject.tomlは依存関係を記したフォルダ。pipenvと似ていて便利 まだpoetry.lockは存在しない。 poetry shell を使用した新しいシェルに切り替える。プロジェクト直下のディレクトリにいって行う。 シェルを切り替えることでなんかもろもろの処理が親プロセスに影響しないようにしているっぽい。 パッケージ追加方法 例えば ① [tool.poetry.dev-dependencies] 直下に [tool.poetry.dependencies] pendulum = "^1.4" 等と記載して、 poetry installすると、 Poetryは pyproject.toml に並べられた全ての依存関係を解決し、それらのファイルの最新バージョンをダウンロードするだけです。 らしい。 ② または、poetry add hoge==x.x.xでもできるらしい。 この段階でpoetry.lockファイルが作成される。これは同じく依存関係を記したものっぽいが、さらに詳細な依存関係まで管理してるっぽい。これを使いまわしてチーム内での動く環境を揃えるらしい。 もし新しい環境にアップデートしたいときは poerty.lockを削除してpoetry installするか、 poetry updateほにゃららを行うとできるらしい。 ※poetryはpyproject.tomlを参照するので、例えば lightgbm = "^3.3.0"は3.3.0以上4未満のパッケージまでしかアップデートできない。 もし4以上が欲しい場合はpyproject.tomlを編集する必要がある 試していませんが、こちらのブログでは、https://zenn.dev/canonrock/articles/poetry_basics poetry add <パッケージ名>@latest でもよいとあります。 tensorflow-gpuの導入まで https://qiita.com/radiol/items/a27530fd33b7e4758e6dに記載のエラーとまったく同じエラーで詰まった。 https://qiita.com/radiol/items/a27530fd33b7e4758e6d 通りにやるとsolveエラーを解決できる pyproject.tomlファイルのnumpy部分を numpy = ">=1.19.2,<1.20.0" に編集してpoetry updateすると以下の表示が出てダウングレードできたっぽい。 Package operations: 0 installs, 3 updates, 0 removals • Updating numpy (1.21.2 -> 1.19.5) • Updating llvmlite (0.36.0 -> 0.37.0) • Updating numba (0.53.1 -> 0.54.1) cuda すでに入ってしまっていたので、コントロールパネル>プログラムのアンインストール的なところで「nvidia」でフィルタリングして削除した その後アーカイブからtensorflowgpuと合致するものをインストール cudnn インストール、pathを通し手動作確認した。 path 一番下のcudnnpathだけ主導で通した poetryの理解 poetry shellした段階で.venvフォルダが作成される。 Creating virtualenv sample in C:\Users\ほげ\poetry-demo\.venvなどと表示される。 poetry-demo └── .venvフォルダ │ ├── Lib │ │ └── site-packages │ └── Scripts │ ├── pip.exe │ └── pytest.exe │ └── python.exe └── poetry.lock └── pyproject.toml └── tests └── readme Lib>site-packages この中に仮想環境内でインストールしたパッケージが入っている。 例えばこの場合numpyやlightgbm等、、、 scripts この中にpipやpython等が入っている poetry.lock 例 [[package]] name = "numpy" version = "1.19.5" description = "NumPy is the fundamental package for array computing with Python." category = "main" optional = false python-versions = ">=3.6" numpyのバージョンや必要とするpythonのバージョンが記載してある事がわかる。 参考にさせていただいたブログ・情報 https://tomiylab.com/2021/03/win-python/ https://cocoatomo.github.io/poetry-ja/basic-usage/ https://zenn.dev/canonrock/articles/poetry_basics
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

poetry+pyenv-win

この記事is何 poetry_pyenv-winの導入の備忘録。 poetryについて(途中) tensorflow-gpuの導入まで(途中) 自分のPC windows 10 pro pyenv portry pyenv-win,poetryの導入 pyenv-winのインストール↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ git clone https://github.com/pyenv-win/pyenv-win.git ~/.pyenv_win PATHを先頭に追加 C:\Users\ほげ\.pyenv_win\pyenv-win\bin C:\Users\ほげ\.pyenv_win\pyenv-win\shims この時点でshimsは存在しないが、これも通していいらしく、これを通さないと pyenv versions が認識されない pyenv install -l で使いたいpythonのバージョンを確認し pyenv install 3.8.0 などと指定しpythonをインストール、tensorflow-gpuを使用したかったのでcolabの3.7.12と近づけて新しめの3.8.0を持ってきた pyenv global 3.8.0 で全体にデフォルトで3.8.0を使うように設定。 poetry↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ (Invoke-WebRequest -Uri https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py -UseBasicParsing).Content | python この方法だとpoetryが1.2.0以上には新しくならないらしい。 バージョンを確認 poetry --version > 仮想環境をプロジェクトのディレクトリ直下に作成するために、以下のコマンドを実行しておく これはちょっとよくわかってないが、おそらくデフォルトで作られるプロジェクトの位置が何かの変数で定められていてそれを変更するものだと思われる。 poetry config virtualenvs.in-project true プロジェクト作成からパッケージインストールの流れ anacondaに慣れていたので、若干戸惑った。以下の通り。 1.プロジェクトディレクトリに入る 2.仮想環境(shell)を起動 3.パッケージを追加・削除・スクリプトを実行など、anacondaでactivateした後のことがすべてできる。変更はpyproject.tomlに記載する/直接コマンドをたたく/poetry.lockに手を加えるなどの方法で行う。 poetry new projectname で新しいプロジェクトを作成。↓のやつが作られる。 poetry-demo ├── pyproject.toml ├── README.rst ├── poetry_demo │ └── __init__.py └── tests ├── __init__.py └── test_poetry_demo.py pyproject.tomlは依存関係を記したフォルダ。pipenvと似ていて便利 まだpoetry.lockは存在しない。 poetry shell を使用した新しいシェルに切り替える。プロジェクト直下のディレクトリにいって行う。 シェルを切り替えることでなんかもろもろの処理が親プロセスに影響しないようにしているっぽい。 パッケージ追加方法 例えば ① [tool.poetry.dev-dependencies] 直下に [tool.poetry.dependencies] pendulum = "^1.4" 等と記載して、 poetry installすると、 Poetryは pyproject.toml に並べられた全ての依存関係を解決し、それらのファイルの最新バージョンをダウンロードするだけです。 らしい。 ② または、poetry add hoge==x.x.xでもできるらしい。 この段階でpoetry.lockファイルが作成される。これは同じく依存関係を記したものっぽいが、さらに詳細な依存関係まで管理してるっぽい。これを使いまわしてチーム内での動く環境を揃えるらしい。 もし新しい環境にアップデートしたいときは poerty.lockを削除してpoetry installするか、 poetry updateほにゃららを行うとできるらしい。 ※poetryはpyproject.tomlを参照するので、例えば lightgbm = "^3.3.0"は3.3.0以上4未満のパッケージまでしかアップデートできない。 もし4以上が欲しい場合はpyproject.tomlを編集する必要がある 試していませんが、こちらのブログでは、https://zenn.dev/canonrock/articles/poetry_basics poetry add <パッケージ名>@latest でもよいとあります。 tensorflow-gpuの導入まで https://qiita.com/radiol/items/a27530fd33b7e4758e6dに記載のエラーとまったく同じエラーで詰まった。 https://qiita.com/radiol/items/a27530fd33b7e4758e6d 通りにやるとsolveエラーを解決できる pyproject.tomlファイルのnumpy部分を numpy = ">=1.19.2,<1.20.0" に編集してpoetry updateすると以下の表示が出てダウングレードできたっぽい。 Package operations: 0 installs, 3 updates, 0 removals • Updating numpy (1.21.2 -> 1.19.5) • Updating llvmlite (0.36.0 -> 0.37.0) • Updating numba (0.53.1 -> 0.54.1) cuda すでに入ってしまっていたので、コントロールパネル>プログラムのアンインストール的なところで「nvidia」でフィルタリングして削除した その後アーカイブからtensorflowgpuと合致するものをインストール cudnn インストール、pathを通し手動作確認した。 path 一番下のcudnnpathだけ主導で通した poetryの理解 poetry shellした段階で.venvフォルダが作成される。 Creating virtualenv sample in C:\Users\ほげ\poetry-demo\.venvなどと表示される。 poetry-demo └── .venvフォルダ │ ├── Lib │ │ └── site-packages │ └── Scripts │ ├── pip.exe │ └── pytest.exe │ └── python.exe └── poetry.lock └── pyproject.toml └── tests └── readme Lib>site-packages この中に仮想環境内でインストールしたパッケージが入っている。 例えばこの場合numpyやlightgbm等、、、 scripts この中にpipやpython等が入っている poetry.lock 例 [[package]] name = "numpy" version = "1.19.5" description = "NumPy is the fundamental package for array computing with Python." category = "main" optional = false python-versions = ">=3.6" numpyのバージョンや必要とするpythonのバージョンが記載してある事がわかる。 参考にさせていただいたブログ・情報 https://tomiylab.com/2021/03/win-python/ https://cocoatomo.github.io/poetry-ja/basic-usage/ https://zenn.dev/canonrock/articles/poetry_basics
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

再帰関数の処理される順番

Pythonでアルゴリズムの学習中に再帰関数を学んだが、「再帰関数でループしたらその下の行の処理いかないんじゃね?」みたいな感じで処理の順番があやふやなところが多いので、下の例を実装しながら理解を深めていく。 再帰関数とは 定義中の関数の中で、その関数(自分自身)が呼び出される関数のこと。「再帰呼び出し」とも呼ばれる。 繰り返し処理などで使われる。 実装 再帰関数totalでどのような値が出力されるか考える。 Python def total(data): if data <= 1: return data value = total(data - 1) return sum(value) def sum(value): return value + 3 print(total(3)) まず、引数に3が入れられたtotal関数が呼び出される。ここで、引数dataが1以下の場合は「1」が返されるが、現状は3なので無視。 次に、変数valueが定義されているが、ここで同じ関数が呼び出される(再帰呼び出し)。引数はdata - 1なので、2になる。ここではreturn sum(value)に進まず、total関数が再び上から処理される。引数dataは2で1以上なのでdataはreturnされず、再び変数valueが定義される(引数は1)。ここでついに引数dataが1になったので、1がreturnされ(無限ループすることはない)、引数が2のtotal関数の変数valueの値は1になる。そして、return sum(value)に進むことができる。 sum関数は引数に+ 3した値を返すだけなので、ここでは1 + 3で4が返される。ここで、引数が2のtotal関数は4が返されたので、引数が3のtotal関数の変数valueに4が与えられる。そして、return sum(value)に進み、4 + 3で7が返され、7が出力される(引数が3のtotal関数を出力するのでこれで終わり)。 まとめ 様々なソートのアルゴリズムで難しい再帰関数の使われ方がされており、理解に苦しんでいたが、これを機に少しは楽になった。再帰関数はあまり使うことはないと思うが、頭の片隅にでも入れておくと良いだろうと思った。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

公式APIを使わずにTwitter Analytics(アナリティクス)の情報を取得する方法

概要 先日、とある業務の一環において「Twitter Analyticsの情報(上記画像のような部分)を毎日記録しておいてくれ」といった感じの指令を受けました。 一応、Twitter Analyticsのページ(https://analytics.twitter.com)では過去にさかのぼって各種データをCSV形式でエクスポートしたりといった機能が用意されていたりするものの、さすがに毎日ここを開いて逐一確認するのはナンセンスというか、曲がりなりにもプログラマーである自分がわざわざやるべき仕事ではないなと感じたため、何とか自動化できる手段は無いかと模索していたわけです。 そうなると真っ先に候補として挙がってくるのは「API経由での取得」ですが、ぱっと見、Twitter AnalyticsのデータをAPI経由で取得するための方法というのが簡単には出できませんでした。 仮に出てきたとしても、 可能ではあるが、広告を出稿したりするためのエンタープライズ用のアカウントでないと無理 Twitter API v2 なら取得できるが、過去30日のみのデータに限られる そもそもそれらを使用するための審査が厳しい といった感じでやや一癖ありそうな雰囲気...。 とりあえず、通常のTwitter APIのようにサードパーティ製のライブラリが充実していて「APIキーさえ取得できれば後はサンプル通りのコードを書けばOK!」みたいな軽いノリでは上手くいかないんだろうなぁと悟ってしまったわけですね。(もしかすると自分のリサーチが甘いだけかもしれませんが...) 中には「Seleniumで自動ログインしてスクレイピングすれば良いやん」といった声もあり、実際にそれっぽいコードを見かけたりもしたものの、Twitter社のスクレイピング嫌いは非常に有名で対策も頻繁に行われているそうなので安定感という点では欠けます。(変にいじくり回すとペナルティ食う可能性などもありますし) で、他に何か手軽な手段は無いか試行錯誤してみたところ、意外と簡単な方法でイケたのでメモ書きしておきます。 cURLコマンドを使う 先に結論から言ってしまうと、cURLコマンドを使います。 そもそもこの画面上の数字がどこから送られてきているのか、デベロッパーツールの「ネットワーク」から確認してみましょう。 すると、 summary.json top_tweet.json page_summary.json panels.json などそれっぽいものがいくつか見つかるはず。したがって、これらにリクエストを送れば何となく取得できそうな気配がしますよね。 試しに「summary.json」にリクエストを送ってみたいと思います。 Google Chromeのデベロッパーツールなら「右クリック → コピー → cURLとしてコピー」でそのままコマンドをコピーできるので便利です。 curl 'https://analytics.twitter.com/user/******(ユーザー名)/home/summary.json?start_time=1631836800000&end_time=1634256000000' \ -H 'authority: analytics.twitter.com' \ -H 'pragma: no-cache' \ -H 'cache-control: no-cache' \ -H 'sec-ch-ua: "Chromium";v="94", "Google Chrome";v="94", ";Not A Brand";v="99"' \ -H 'accept: application/json, text/javascript, */*; q=0.01' \ -H 'x-requested-with: XMLHttpRequest' \ -H 'sec-ch-ua-mobile: ?0' \ -H 'user-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.81 Safari/537.36' \ -H 'sec-ch-ua-platform: "macOS"' \ -H 'sec-fetch-site: same-origin' \ -H 'sec-fetch-mode: cors' \ -H 'sec-fetch-dest: empty' \ -H 'referer: https://analytics.twitter.com/user/******(ユーザー名)/home' \ -H 'accept-language: ja,en-US;q=0.9,en;q=0.8' \ -H 'cookie: kdt=********************; remember_checked_on=1; des_opt_in=Y; cd_user_id=**********************; dnt=1; lang=ja; _gid=***************; personalization_id="************"; guest_id=**************; gt=***************; _twitter_sess=********************; auth_token=******************; twid=****************; ct0=****************; att=********************; csrf_id=*******************; at_check=true; _gcl_au=*********************; mbox=PC#******************#***********|session#*****************#*************; _ga=***************; _ga_*************=******************' \ --compressed クリップボードに↑のようなコマンドがコピーされていればOK。 これを実行してみると、次のような形式のレスポンスが返ってくるはずです。 { "html": "<div class=\"row\">\n <div class=\"col-md-10\">\n <div class=\"home-summary-panel\">\n\n <div class=\"home-summary-metric DataPoint\" data-metric=\"tweets\" title=\"30\">\n <div class=\"DataPoint-label\">ツイート</div>\n <div class=\"DataPoint-info\">30\n <span class=\"DataPoint-trend DataPoint-trend--positive\">15.4%</span>\n\n </div>\n <div class=\"home-summary-chart\"></div>\n </div>\n\n <div class=\"home-summary-metric DataPoint\" data-metric=\"tweetviews\" title=\"3,118\">\n <div class=\"DataPoint-label\">ツイートインプレッション</div>\n <div class=\"DataPoint-info\">3,118\n <span class=\"DataPoint-trend DataPoint-trend--positive\">13.5%</span>\n\n </div>\n <div class=\"home-summary-chart\"></div>\n </div>\n\n <div class=\"home-summary-metric DataPoint\" data-metric=\"profileviews\" title=\"988\">\n <div class=\"DataPoint-label\">プロフィールへのアクセス</div>\n <div class=\"DataPoint-info\">988\n <span class=\"DataPoint-trend DataPoint-trend--negative\">26.8%</span>\n\n </div>\n <div class=\"home-summary-chart\"></div>\n </div>\n\n <div class=\"home-summary-metric DataPoint\" data-metric=\"mentions\" title=\"19\">\n <div class=\"DataPoint-label\">@ツイート</div>\n <div class=\"DataPoint-info\">19\n <span class=\"DataPoint-trend DataPoint-trend--positive\">46.2%</span>\n\n </div>\n <div class=\"home-summary-chart\"></div>\n </div>\n\n <div class=\"home-summary-metric DataPoint\" data-metric=\"followers\" title=\"547\">\n <div class=\"DataPoint-label\">フォロワー数</div>\n <div class=\"DataPoint-info\">547\n <span class=\"DataPoint-trend DataPoint-trend--negative\">-3</span>\n\n </div>\n <div class=\"home-summary-chart\"></div>\n </div>\n\n </div>\n </div>\n</div>\n", "domain": [ *************, ************* ], "step": **********, "timeseries": { "followers": [ [ ***************, 550 ], ... ], "mentions": [ [ ***************, 0 ], ... ], "tweetviews": [ [ ***************, 118 ], ... ], "profileviews": [ [ ***************, 14 ], ... ], "tweets": [ [ ***************, 0 ], ... ] } } どうやらそれっぽいデータが取得できてますね。 あとはこのJSONをパースして煮るなり焼くなり好きにすればOK。 他のデータ(top_tweet、page_summary、panelsなど)も同様のやり方で取得できるので試してみてください。 ※ 返ってきたデータが文字化けなどしている場合、末尾に | perl -Xpne 's/\\u([0-9a-fA-F]{4})/chr(hex($1))/eg' を追記して実行すると解決できるかもしれません。 RubyやPythonで処理したい場合 ここからは番外編なので、必要無ければ読み飛ばしていただいて結構です。 ただデータを取得するだけならcURLコマンドで足りるかもしれませんが、色々とデータをこねくり回そうと思ったら何らかのプログラミング言語が必要になると思うので、参考にしていただければと思います。 Ruby まずRubyから。 gemをインストール ./Gemfile # frozen_string_literal: true source "https://rubygems.org" git_source(:github) {|repo_name| "https://github.com/#{repo_name}" } gem "dotenv" gem "faraday" gem "nokogiri" $ bundle install --path vendor/bundle 秘匿情報を扱うための「dotenv」 HTTPリクエストを送信するための「faraday」 HTML解析を行うための「nokogiri」 などをインストールしておきます。 環境変数をセット ./.env TWITTER_USERNAME=<Twitterのユーザー名> TWITTER_AUTH_TOKEN=<認証トークン> 先ほど生成したcURLコマンド内のヘッダーには色々ごちゃごちゃした情報が付与されていましたが、実は認証トークンだけで十分だったりします。 「-H 'cookie: 」から「auth_token」だけ抜き出して「TWITTER_AUTH_TOKEN」にセットしてください。 コード ./main.rb require "bundler/setup" require "faraday" require "nokogiri" require "json" require "dotenv" Dotenv.load # Twitter Analyticsの情報を取得するためのクラス class TwitterAnalytics def initialize(username, auth_token) @client = Faraday.new(url: "https://analytics.twitter.com/user/#{username}/home") do |req| req.headers["Cookie"] = "auth_token=#{auth_token}; lang=ja;" end end # データを取得 def fetch_data(category, start_time, end_time) @client.get "#{category}.json?start_time=#{start_time}&end_time=#{end_time}" end end # 取得したいデータのカテゴリを指定 category = "summary" # 取得開始日時と取得終了日時をUnixtimeで指定 start_time = 1631836800000 end_time = 1634256000000 # リクエストを送信 ta = TwitterAnalytics.new(ENV["TWITTER_USERNAME"], ENV["TWITTER_AUTH_TOKEN"]) res = ta.fetch_data(category, start_time, end_time) # NokogiriでHTML解析 html = JSON.parse(res.body)["html"] doc = Nokogiri::HTML(html) # 各種データを取り出し metrics = doc.css(".home-summary-metric") tweets = metrics[0].attr("title") tweet_views = metrics[1].attr("title") profile_views = metrics[2].attr("title") mentions = metrics[3].attr("title") followers = metrics[4].attr("title") heredoc = <<~EOS ツイート: #{tweets} ツイートインプレッション: #{tweet_views} プロフィールへのアクセス: #{profile_views} @ツイート: #{mentions} フォロワー数: #{followers} EOS puts heredoc 大体こんな感じで良いでしょう。 $ bundle exec ruby main.rb ツイート: 30 ツイートインプレッション: 3,127 プロフィールへのアクセス: 988 @ツイート: 19 フォロワー数: 547 実際のTwitter Analytics画面とも数字が一致しているので大丈夫そうですね!(個人アカウントを試しているので全体的な数字がショボいのは勘弁してください...) Python こういう作業はPythonでやりたいという方もいると思うので、一応Python版も掲載しておきます。 ライブラリをインストール ./requirements.txt python-dotenv requests beautifulsoup4 $ pip install -r requirements.txt 秘匿情報を扱うための「python-dotenv」 HTTPリクエストを送信するための「requests」 HTML解析を行うための「beautifulsoup4」 などをインストールしておきます。 環境変数をセット ./.env TWITTER_USERNAME=<Twitterのユーザー名> TWITTER_AUTH_TOKEN=<認証トークン> 先ほど(Ruby版)と同じなので説明は割愛。 コード ./main.py import os import json import requests import textwrap from bs4 import BeautifulSoup from dotenv import load_dotenv load_dotenv() # Twitter Analyticsの情報を取得するためのクラス class TwitterAnalytics: def __init__(self, username, auth_token): self.username = username self.auth_token = auth_token # データを取得 def fetch_data(self, category, start_time, end_time): url = f"https://analytics.twitter.com/user/{self.username}/home/{category}.json?start_time={start_time}&end_time={end_time}" headers = { "Cookie": f"auth_token={self.auth_token}; lang=ja" } return requests.get(url, headers=headers) # 取得したいデータのカテゴリを指定 category = "summary" # 取得開始日時と取得終了日時をUnixtimeで指定 start_time = 1631836800000 end_time = 1634256000000 # リクエストを送信 ta = TwitterAnalytics(os.getenv("TWITTER_USERNAME"), os.getenv("TWITTER_AUTH_TOKEN")) res = ta.fetch_data(category, start_time, end_time) # BeautifulSoupでHTML解析 html = res.json()["html"] soup = BeautifulSoup(html, "html.parser") # 各種データを取り出し metrics = soup.find_all("div", class_ = "home-summary-metric") tweets = metrics[0]["title"] tweet_views = metrics[1]["title"] profile_views = metrics[2]["title"] mentions = metrics[3]["title"] followers = metrics[4]["title"] heredoc = textwrap.dedent(""" ツイート: {tweets} ツイートインプレッション: {tweet_views} プロフィールへのアクセス: {profile_views} @ツイート: {mentions} フォロワー数: {followers} """).format( tweets = tweets, tweet_views = tweet_views, profile_views = profile_views, mentions = mentions, followers = followers ) print(heredoc) あとはコイツを実行すればOK。 $ python main.py ツイート: 30 ツイートインプレッション: 3,127 プロフィールへのアクセス: 988 @ツイート: 19 フォロワー数: 547 と返ってくるはずです。 あとがき 以上、APIなどを使用せずにTwitter Analytics(アナリティクス)の情報を取得してみました。もし同じような事を再現したい方は参考にしてみてください。 なお、この方法が果たしてTwitter側からして良いものであると見なされるとは限らないのでご注意を。もしかしたらある日急に使えなくなる可能性も十分にあります。 あと、auth_tokenの有効期限がどれくらいかわからないため、完全自動化を図ろうとする場合はその辺の回転も意識して工夫が必要になるかも...。 とにもかくにも、常識の範囲内で試していただけると幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ABC180 C - Cream puff から学んだ

WA が抜けない。 他の人の回答を読んで叫ぶ(笑) abc180c.py from math import * N = int(input()) lis=[] if N == 1: print(1) exit() for i in range(1,floor(sqrt(N))+1): if N%i == 0: lis.append(i) lis.append(N//i) lis = list(set(lis))#<= ココ を忘れると WA lis.sort() for ans in lis: print(ans)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む