20211125のPythonに関する記事は30件です。

Python リスト

title: Python リスト tags: Python Python3 author: Hirakawa123 slide: false はじめに 基礎から定着させていこうということでリストについてまとめました。 Python 3.8.2 リストの作成 l = [1,2,3,4,5,6,7,8] リストを表示する l = [1,2,3,4,5,6,7,8] print(l) リストのタイプの確認 l = [1,2,3,4,5,6,7,8] print(type(l)) リストにいくつ値が入っているのか l = [1,2,3,4,5,6,7,8] print(len(l)) リストの一部を取得する l = [1,2,3,4,5,6,7,8] print(l[0]) print(l[-1]) print(l[1:3]) print(l[:6]) リストのスキップして取得する l = [1,2,3,4,5,6,7,8] print(l[::2]) リストの書き換え l = ["a","s","d","f"] l[1] = "b" print(l[1]) print(l) リストの複数の値の書き換え l = ["a","s","d","f"] l[2:4] = ["c","d"] print(l) リストの中身を空する l[1:3] = [] print(l) リストに追加するメソッド1 n = [1,2,3,4,5] print(n) n.append(6) print(n) リストに追加するメソッド2 n = [1,2,3,4,5] n.insert(0,0) print(n) リストから値を取り除くメソッド n = [1,2,3,4,5] n.pop() print(n) n.pop(0) print(n) リストの削除 n = [1,2,3,4,5] del n[0] print(n) リストの自体の削除を行ったため、printしてもnが定義されていないと出力される。 n = [1,2,3,4,5] del n print(n) 値に一致するものを削除する n = [1,2,3,4,5] #3番目の位置にある値ではなく、3の値を取り除く n.remove(3) print() リストの結合 l1 = [1,2,3] l2 = [10,20,30] l3 = l1 + l2 print(l3) l1 += l2 print(l1) l1.extend(l3) print(l1) 値がどこの位置に入っているかを確認するメソッド l = [1,2,3,4,5,4,3,2,1] print(l.index(3)) ##3を-3番目以降から探している print(l.index(3,-3)) 値の個数をカウント l = [1,2,3,4,5,4,3,2,1] print(l.count(6)) リストのソート l = [1,2,3,4,5,4,3,2,1] l.sort() print(l) ソート&リバース l = [1,2,3,4,5,4,3,2,1] l.sort(reverse=True) print(l) リストのリバース n = [1,2,3,4,5] print(n) n.reverse() print(n) スプリット x = "I have a pen" to_split = x.split(" ") print(to_split) #スプリットをもとに戻す y = " ".join(to_split) print(y) ネストの作成 l1 = [1,2,3] l2 = [10,20,30] x = [l1,l2] print(x) ネストの取り出し方 x = [[1,2,3],[10,20,30]] print(x[0]) print(x[0][1])
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pythonでのスクレイピング

HTTP通信でHTMLを取得して解析する方法。 APIでJSON取得が出来ると良いが、そういうものが見つからない場合にスクレイピング的にHTMLから取得したい。 環境はWindowsServer2012+Python3.9.7 パース HTMLのパースには import bs4 # beautifulsoup4 XMLパーサ を利用する。 pipで取得して以下のようにしてセレクタを使って取得したりする。 selector = "#items" soup = bs4.BeautifulSoup(html, "html.parser") # パーサーに渡す result = soup.find(selector) request 実際にHTMLを取得する方法だが、2つ存在する。 1つはPythonからhttpリクエストを投げてデータを取得する方法。 もう一つはブラウザ経由で取得、つまりReact等で構成されたページの内容を取得する方法。 requestsは一つ目の方法で、簡単に利用できる。 パースと組み合わせた簡単な処理は以下のような感じ。 公式とか参照。 def htmlSearch(key): proxies = { "http":"http://proxy:8080", "https":"http://proxy:8080" } params = {'q': key} # ここの書き方が正しいかは見てない url = "https://www.target.com" + key # URLがキーになっている場合 selector = "#items" req = requests.get(url,proxies=proxies,params=params) print(req.url) print(req.text) soup = bs4.BeautifulSoup(req.text, "html.parser") # パーサーに渡す result = soup.find(selector) print(result) # findは先頭の1件のみなのでget_textが可能 return result Selenium ブラウザコントロールのパターン。今回はこれがメイン。Chromeをコントロールする。 ここがある程度参考になりそうだが、バージョン違いなのか、一部上手く行かない事もあった。 まずはpip install seleniumでインストール。 pipでプロキシ使う場合はpip install --proxy="http://proxy:8080" seleniumとする。 Chromeを操作するにはChromeDriverが必要なのでダウンロードしておく。 Python内ではdriver = webdriver.Chrome(executable_path='G:/apps/chromedriver_win32/chromedriver.exe')のように設定。 設定が間違っているとchromedriver_win32 executable needs to be in PATH.が出る。 これでdriver.get(url)でChromeにURLを与える事が出来る。 今回入力操作は不要なので省略。 検索結果から値を取得するが、SeleniumにXPathを利用した取得機能が付いているのでそれを利用する。 実際にはReactでの読み込みに少し時間がかかるので待機が必要。 time.sleepやdriver.implicitly_waitを使う。 基本形はこのような形 from selenium import webdriver from time import sleep from selenium.webdriver.chrome.options import Options # key sample: /p/6891/0196/ def chromeSearch(key): try: driver = webdriver.Chrome(executable_path='G:/apps/chromedriver_win32/chromedriver.exe') options = Options() # options.add_argument('--headless') # ヘッドレスモード url = "https://www.target.com" + key selector = '//*[@id="items"]/div[1]/div[3]/div[1]/div[1]/span' # 実際にはXPath検索 sleep(1) # 念のため待つ driver.get(url) driver.implicitly_wait(10) # findで要素が見つかるまで最大10秒待機 result = driver.find_element_by_xpath(selector) print(result.text) # 使い終わったら閉じる finally: driver.close() driver.quit() return result.text 実際にはExcelから読み込んで連続検索したりしたいので、外部からdriverを渡すようなメソッドを作る方が良さそう。 上記ソースでブラウザからの取得は上手くいったが、headlessオプションを付けると上手くいかない、といった挙動が発生した。 いくつか情報があって、ブラウザサイズの問題や、サーバ側でヘッドレスモードを弾こうとしている、といったもの。 ヘッドレスが弾かれる場合はヘッダーを偽装する手法は取れそう。 from fake_headers import Headers header = Headers( browser="chrome", # Generate only Chrome UA os="win", # Generate only Windows platform headers=False # generate misc headers ) customUserAgent = header.generate()['User-Agent'] options.add_argument("user-agent={customUserAgent}") とりあえず画面サイズとヘッダ偽装を両方実装する事で対応出来た。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】株価データ分析 株価チャートを描く~mplfinance編 その1~

はじめに 前回の【Python】東証上場銘柄の株価データを取得する(その2)では pandas_datareader を使って株価データを取得した Python で株価チャートを描くには mplfinace,plotly を使うのがよさそうで, 今回は取得した株価データをmplfinanceを使って株価チャートを描いてみたい まずは,mplfinace編 その1として,いくつかのチャートを描いてみたい 本記事を書く上で,matplotlib/mplfinanceを参考にしている 準備 まずはともかく,mplfinance のインストールをする conda の場合 conda install mplfinance pip の場合 pip install mplfinance データ用意 自分銘柄一覧(my.xlsx)と東証上場銘柄一覧(date_j.xls)を読み込む 前回を参考にしてほしいが,自分銘柄一覧(my.xlsx)とは,自分の保有銘柄の一覧で(仮に,トヨタ,日産,ホンダ,ANA,JALを保有しているとしている), 東証上場銘柄一覧(data_j.xls)とは,日本取引所グループにある東証上場銘柄の一覧ファイルのことだ まずは,自分銘柄と東証上場銘柄一覧を読み込んで,自分銘柄のDataFrameを作る import pandas as pd import pandas_datareader.data as pdr import datetime from dateutil.relativedelta import relativedelta ## 自分銘柄と東証上場銘柄一覧を読み込む my_df = pd.read_excel('my.xlsx', sheet_name = 'Sheet1', dtype = str) topix_df = pd.read_excel('data_j.xls', dtype = str) ## 自分銘柄のDataFrameを作る code_set = set(my_df['コード'].tolist()) df = topix_df[topix_df['コード'].isin(code_set)] df 日付 コード 銘柄名 市場・商品区分 33業種コード 33業種区分 17業種コード 17業種区分 規模コード 規模区分 2886 20211029 7201 日産自動車 市場第一部(内国株) 3700 輸送用機器 6 自動車・輸送機 2 TOPIX Large70 2888 20211029 7203 トヨタ自動車 市場第一部(内国株) 3700 輸送用機器 6 自動車・輸送機 1 TOPIX Core30 2926 20211029 7267 本田技研工業 市場第一部(内国株) 3700 輸送用機器 6 自動車・輸送機 1 TOPIX Core30 3793 20211029 9201 日本航空 市場第一部(内国株) 5150 空運業 12 運輸・物流 4 TOPIX Mid400 3794 20211029 9202 ANAホールディングス 市場第一部(内国株) 5150 空運業 12 運輸・物流 2 TOPIX Large70 チャートを描き方を学ぶのが目的なので,先頭の銘柄(日産自動車)だけにしておく code = df['コード'].tolist()[0] company = df['銘柄名'].tolist()[0] 6か月分のデータを取得 ed = datetime.datetime.now() # 本日 st = ed - relativedelta(months = 6) # 6か月前 df = pdr.DataReader(code + '.T', 'yahoo', st, ed) これでデータの準備はできた ローソク足を描く import mplfinance as mpf mpf.plot(data = df, type = 'candle') mplfinance をインポートして,plot 関数を呼ぶ plot に渡す data は,DataFrame で,Open,High,Low,Closeの列が必要 index は,DatetimeIndex の必要がある pandas_datareaderを使って取得した株価データは,これらの要件を満たしているので何も考えなくてもよい >>> type(df) pandas.core.frame.DataFrame >>> df.columns Index(['High', 'Low', 'Open', 'Close', 'Volume', 'Adj Close'], dtype='object') >>> type(df.index) pandas.core.indexes.datetimes.DatetimeIndex 出来高を表示する volume = True とするだけでよい mpf.plot(df, type = 'candle', volume = True) 移動平均を表示する mavで日数を渡せばよい 2つでも,3つでも日数を並べればよい mpf.plot(df, type = 'candle', volume = True, mav = (9,17)) mpf.plot(df, type = 'candle', volume = True, mav = (9,17,26)) スタイルを変える まずはよく使う設定の辞書を作っておく kwargs = dict(type = 'candle', volume = True, mav = (9,17,26)) 使えるスタイルは >>> mpf.available_styles() ['binance', 'blueskies', 'brasil', 'charles', 'checkers', 'classic', 'default', 'ibd', 'kenan', 'mike', 'nightclouds', 'sas', 'starsandstripes', 'yahoo'] yahoo ## yahoo mpf.plot(df, **kwargs, style = 'yahoo') starsandstripes ## starsandstripes mpf.plot(df, **kwargs, style = 'starsandstripes') 線を引く 期間内の,高値と安値に線を引いてみる ちなみに,高値と安値は >>> df['High'].max(), df['Low'].min() (654.2999877929688, 516.5) 設定の辞書でyahooにしておく kwargs = dict(type = 'candle', volume = True, mav = (9,17,26), style = 'yahoo') hlines で横線を引く際の y座標(株価)を指定する 終値ベースでの高値と安値 mpf.plot(df, **kwargs, hlines = [df['Close'].max(), df['Close'].min()]) ちょっと線が太いので,線幅を指定する (終値から,高値,安値に変えておく) 先ほどは,hlines にリストを渡していたが,辞書を渡す 辞書にy座標(株価)と線幅を渡す mpf.plot(df, **kwargs, hlines = dict(hlines=[df['High'].max(), df['Low'].min()], linewidths=(.5, .5))) うん,細くなった,素敵 次は,安値と高値を結んだ線を引いてみる 高値をとった日は >>> df['High'].idxmax() Timestamp('2021-11-19 00:00:00') 安値をとった日は >>> df['Low'].idxmin() Timestamp('2021-10-07 00:00:00') 設定の辞書でstarsandstripesにしておいて, ごちゃごちゃしてきそうなので,移動平均もついでにやめておく kwargs = dict(type = 'candle', style = 'starsandstripes') alines に,2点の座標(安値と高値)を渡す必要があるので, two_points に,安値の座標(安値をとった日付,安値)と高値の座標(高値をとった日付,高値)を設定する two_points = [(df['High'].idxmax(), df['High'].max()),(df['Low'].idxmin(),df['Low'].min())] mpf.plot(df, **kwargs, hlines = dict(hlines=[df['High'].max(), df['Low'].min()], linewidths=(.5, .5), colors=('r','r')), alines = dict(alines=two_points, linewidths=(.5), colors=('b'))) いいね! 線を太くし,透かす それぞれ,linewidth,alphaで設定する mpf.plot(df, **kwargs, hlines = dict(hlines=[df['High'].max(), df['Low'].min()], inewidths=(.5, .5), colors=('r','r')), alines = dict(alines=two_points, linewidths=(40), colors=('b'), alpha=0.2)) いいね!! グラフをファイルに出力する savefig に,ファイル名(fname)とDPIを与える mpf.plot(df, **kwargs, hlines = dict(hlines=[df['High'].max(), df['Low'].min()], linewidths=(.5, .5), colors=('r','r')), alines = dict(alines=two_points, linewidths=(40), colors=('b'), alpha=0.2), savefig=dict(fname='nissan.png',dpi=100)) おわりに 今回は,株価チャートを mplfinance を使って描いてみた 次回は,MACDやボリンジャーバンドを描いたり, 複数銘柄を並べて描くようなことをやってみたい
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

自然言語処理100本ノック2020を解いてみた(第一章)

はじめに 自然言語処理100本ノック2020の第一章を解いてみました。 動かしてみたい場合は、こちらのNotebook(Google Colaboratory)から、簡単に実行できます。 00. 文字列の逆順 文字列”stressed”の文字を逆に(末尾から先頭に向かって)並べた文字列を得よ. python text = "stressed" ans = text[::-1] print(ans) output desserts 01. 「パタトクカシーー」 「パタトクカシーー」という文字列の1,3,5,7文字目を取り出して連結した文字列を得よ. python text = "パタトクカシーー" ans = text[::2] print(ans) output パトカー 02. 「パトカー」+「タクシー」=「パタトクカシーー」 「パトカー」+「タクシー」の文字を先頭から交互に連結して文字列「パタトクカシーー」を得よ. python text1 = "パトカー" text2 = "タクシー" ans = "".join([c1+c2 for c1, c2 in zip(text1, text2)]) print(ans) output パタトクカシーー 03. 円周率 “Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics.”という文を単語に分解し,各単語の(アルファベットの)文字数を先頭から出現順に並べたリストを作成せよ. python text = "Now I need a drink, alcoholic of course, after the heavy lectures involving quantum mechanics." text_replaced = text.replace(".", "").replace(",", "") ans = [len(w) for w in text_replaced.split()] print(ans) output [3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9] 04. 元素記号 "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can."という文を単語に分解し,1, 5, 6, 7, 8, 9, 15, 16, 19番目の単語は先頭の1文字,それ以外の単語は先頭の2文字を取り出し,取り出した文字列から単語の位置(先頭から何番目の単語か)への連想配列(辞書型もしくはマップ型)を作成せよ. python text = "Hi He Lied Because Boron Could Not Oxidize Fluorine. New Nations Might Also Sign Peace Security Clause. Arthur King Can." head_idxes = [1, 5, 6, 7, 8, 9, 15, 16, 19] text_replaced= text.replace(".", "") ans = dict([(w[0], i+1) if i+1 in head_idxes else (w[:2], i+1) for i, w in enumerate(text_replaced.split())]) print(ans) output {'H': 1, 'He': 2, 'Li': 3, 'Be': 4, 'B': 5, 'C': 6, 'N': 7, 'O': 8, 'F': 9, 'Ne': 10, 'Na': 11, 'Mi': 12, 'Al': 13, 'Si': 14, 'P': 15, 'S': 16, 'Cl': 17, 'Ar': 18, 'K': 19, 'Ca': 20} 05. n-gram 与えられたシーケンス(文字列やリストなど)からn-gramを作る関数を作成せよ.この関数を用い,”I am an NLPer”という文から単語bi-gram,文字bi-gramを得よ. python text = "I am an NLPer" def n_gram(target, n): return [target[i:i+n] for i in range(len(target)-(n-1))] word_bi_gram = n_gram(text.split(), 2) char_bi_gram = n_gram(text, 2) print(word_bi_gram) print(char_bi_gram) output [['I', 'am'], ['am', 'an'], ['an', 'NLPer']] ['I ', ' a', 'am', 'm ', ' a', 'an', 'n ', ' N', 'NL', 'LP', 'Pe', 'er'] 06. 集合 “paraparaparadise”と”paragraph”に含まれる文字bi-gramの集合を,それぞれ, XとYとして求め,XとYの和集合,積集合,差集合を求めよ.さらに,’se’というbi-gramがXおよびYに含まれるかどうかを調べよ. python text1 = "paraparaparadise" text2 = "paragraph" target = "se" X = set(n_gram(text1, 2)) Y = set(n_gram(text2, 2)) print(f"X: {X}") print(f"Y: {Y}") print(f"和集合: {X | Y}") print(f"積集合: {X & Y}") print(f"差集合: {X - Y}") print(f"'{target}' in X: {target in X}") print(f"'{target}' in Y: {target in Y}") output X: {'ad', 'se', 'pa', 'di', 'is', 'ra', 'ar', 'ap'} Y: {'ph', 'pa', 'gr', 'ra', 'ag', 'ar', 'ap'} 和集合: {'ad', 'se', 'pa', 'ph', 'gr', 'di', 'is', 'ra', 'ag', 'ar', 'ap'} 積集合: {'ar', 'pa', 'ra', 'ap'} 差集合: {'ad', 'is', 'di', 'se'} 'se' in X: True 'se' in Y: False 07. テンプレートによる文生成 引数x, y, zを受け取り「x時のyはz」という文字列を返す関数を実装せよ.さらに,x=12, y=”気温”, z=22.4として,実行結果を確認せよ. python def generate_text(x, y, z): return f"{x}時の{y}は{z}" ans = generate_text(x=12, y="気温", z=22.4) print(ans) output 12時の気温は22.4 08. 暗号文 与えられた文字列の各文字を,以下の仕様で変換する関数cipherを実装せよ. - 英小文字ならば(219 - 文字コード)の文字に置換 - その他の文字はそのまま出力 この関数を用い,英語のメッセージを暗号化・復号化せよ. python def cipher(text): return "".join([chr(219 - ord(c)) if c.islower() else c for c in text]) text = "Test Message" text_enciphered = cipher(text) text_deciphered = cipher(text_enciphered) print(text_enciphered) print(text_deciphered) output Tvhg Mvhhztv Test Message 09. Typoglycemia スペースで区切られた単語列に対して,各単語の先頭と末尾の文字は残し,それ以外の文字の順序をランダムに並び替えるプログラムを作成せよ.ただし,長さが4以下の単語は並び替えないこととする.適当な英語の文(例えば”I couldn’t believe that I could actually understand what I was reading : the phenomenal power of the human mind .”)を与え,その実行結果を確認せよ. python import random text = "I couldn't believe that I could actually understand what I was reading: the phenomenal power of the human mind." def typoglycemia(word): if len(word) > 4: rondom_word = "".join(random.sample(word[1:-1], len(word[1:-1]))) word = word[0] + rondom_word + word[-1] return word ans = " ".join([typoglycemia(w) for w in text.split()]) print(ans) output I cdou'nlt bvleiee that I culod alatucly utdrannsed what I was rinagde: the peaemnonhl pweor of the human mdin.
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

変数とは何か、わかりやすく解説してみた【OBGノウハウ】

どのプログラミング言語を学んでいる上でも絶対必要となる知識がいくつかあると思うのですが、今回は初歩の初歩!変数について私なりの解釈と講習会で使用している説明でのたとえ話なんかをまとめてみました! RPAツールやpythonやjs……どの言語を触っていても必ず付いてくるものですが、逆に言うと理解さえしてしまえば別の言語を触る時にも「アッ……これ、○○でやったやつだ……!」と役に立つ基礎がいくつかあると思っております。 その中で今回は、変数についてまとめてみました! ※今回、変数って何…?というプログラミングにこれから一歩を踏み出すぞ!という方向けに、「変数の概念が何となくわかった気になる」「変数コワクナイ!変数大事!(・∀・)」と思って貰えることを目的として記事を作成しております。 あえて抽象度を高めにしている例え話を用いております。 変数とは何か 変数とは、データを入れるための箱です。 また、箱には「型」と呼ばれる種類が存在します。 日常生活の中でも、「入れ物」に「中身」をいれることってありますよね。 引っ越しの荷造りだったり、ペットボトルに飲み物を入れたり、スーパーのカゴに食材をいれたり……。 例えば、宅配便が届いたとします。 箱の外側に貼られている伝票には「品名:食品」……丁度お腹もすいたし、何が入っているかな~! \パカッ!/ わぁ!あったかそうな毛布が出て来た~! ……なんでやねんっ……!毛布は食べられないわ! 例えば、食事の時。 お茶碗の中に味噌汁が、マグカップの中にほかほかの白米がよそられて提供されました。 ……なんでやねんっ……!(2回目) 何が言いたいかと言いますと、入れ物と中身が一致していないと戸惑っちゃいますよねって話です。 我々人間でさえ戸惑うのですから、より繊細なプログラミング言語はもっと戸惑ってしまいます。 変数を扱う際には型の概念が必須事項になります。具体的な型の名称や種類については後述します! 変数があることのメリット さて、変数=データを入れるための箱、と言うのは理解頂けたかと思います。 じゃあプログラミングをする上で、なぜ変数という型が必要なの?という解説をしていきます。 突然ですがここでまた、例え話をしていきます。 まず、カレーを作るプログラムを作りたいとします。 今回のカレーに使用する材料はじゃがいも、ニンジン、玉ねぎ、鶏肉だとします。 カレーを作るプロセスを大まかに書き出すと、こんな感じでしょうか。 細かい作業は色々ありますが、今回はあえて省いております。 この状態でも確かにカレーは作れますが、色々と不便な場所があります。 汎用性の向上 例えば、今日はカレーの気分じゃないんだよな、肉じゃがが食べたい……。そう思った時に変数を用いていないと、肉じゃがのプログラムを1から作らなければいけません。 もしくは2から4の「じゃがいも、ニンジン、玉ねぎ、鶏肉」をすべて「じゃがいも、ニンジン、玉ねぎ、牛肉、しらたき、しいたけ」と変えなければいけません。ちょっと面倒ですし、我々人間はどうしてもうっかりしてしまう生き物なので変更漏れが出てしまうかもしれません。 そんな時に便利なのが変数です!まずはカレーのプログラムの、1から4のプロセスに1つ追加をして、変数「材料」を使用して書き換えてみます。 ※関数・オブジェクト指向での解決は今回考えておりません。変数の使い方だけに焦点を絞っています。 そして、肉じゃがが食べたい……と思ったら、「1.材料=じゃがいも、ニンジン、玉ねぎ、鶏肉とする」の部分を「1.材料=じゃがいも、ニンジン、玉ねぎ、牛肉、しらたき、しいたけとする」とだけ変えてしまえば良いわけです。 メンテナンス性の向上 扱う材料の内容がカレーの材料から肉じゃがの材料に変更になった……など、データの変更があった際はステップ1の部分だけを変更すればいいのでメンテナンス性も向上しますし、変更漏れの可能性を低くすることも出来ます。 可読性の向上 変数の名前に一目で見て内容が察することが出来るような名前を付けておけば、コードの解読も容易になり可読性が一気に向上します。 変数の命名には規則があるので、それについてはまた後日、詳しく解説していきます。 変数(データ)の型について さて、変数が便利な事は伝わったかと思います! 繰り返しにはなりますが、変数はデータを入れる為の入れ物になります。日常生活で周りを見まわした際に段ボール、カゴ、お茶碗、タンブラーなどなど……色んな種類の入れ物があると思います。そしてその入れ物に適したものを入れる必要があると冒頭でも記述しました。この入れ物の種類の事を「変数の型」と言います。 ここでは代表的な型を紹介していきます。 取り扱えるデータの種類はどの言語も大体同じですが、表記が異なる場合があります。 今回はpythonとUiPathに焦点を当てていこうかと思います。 ちなみに、pythonは変数に値を入力すると自動で型が判定されます。 UiPathに関しては変数の作成方法によって自動で判定されるものもありますが、基本的には自分で変数を作成した際には自分で型を設定する必要があります。 文字列を扱う str型(python) 変数名 = ‘ オブジェクティブグループ ’ ; string(UiPath) 変数名 = “ オブジェクティブグループ “ 数字を扱う 整数 int型(python) 変数名 = 123 ; int32(UiPath) 変数名= 123 小数 float型(python) 変数名= 1.234 ; double(UiPath) 変数名= 1.234 真(true)か偽(false)を扱う bool型(python) 変数名 = True ;(もしくはfalse) boolean(UiPath) 変数名= True(もしくはfalse) 複数のデータを扱う list型(python) 変数名 = [ ‘ apple ’ , ‘ orange ’ , ‘ banana ’ , ‘ peach ’ ] ; tuple型(python) 変数名 = ( ‘ apple ’ , ‘ orange ’ , ‘ banana ’ , ‘ peache ’ ) ; dictionary型(python) 変数名 = { ‘ fruit ’ : ‘ apple ’ ,’ ID ’ : ‘ 001 ’ , ‘ name ’ : ‘ tochiotome ’ } ; Array of [ T ](UiPath) 変数名= { “ apple” , “ orange “ , “ banana ” , “ peach “ } ※変数名(数字)で何番目のデータを表示が出来る UiPath独自の型 Data Table = ExcelやCSVからデータを読み込みしたり、書き込みしたりする際に使用する Generic Value = 文字列型と数値型など複数の型を持つことができる超チート型。困ったらとりあえずGeneric Valueを使っておけばイケる……かと思いきや、チートだからこそエラーの原因になることも。こいつだけ使えればOKという訳ではない…。 変数の宣言の仕方は言語によって異なるので、自分がよく触る言語の変数の仕方については手を動かしている内に身についてくるかと思います。 次回は変数の命名についてもまとめてみたいと思います!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

FastAPI OAuth2 クライアント

FastAPI OAuth2パスワード認証 - Qiita 前回、QiitaにてFastAPIのパスワード認証について書きましたが、クライアント側はSwagger UIを利用したおかげで、パスワードフローの動きのほとんどが隠蔽されていました。プログラム的には以下の公式サイトの前者の方を掲載させていただきました。これはパスワードフローの枠組みをコーディングしているだけで、JWTの暗号的要素を無視したものでした。わかり易いが完全ではない。後者の公式サイトの方はJWTをサポートした完全なパスワードフローです。今回はこれを利用させていただきます。 【公式サイト】Simple OAuth2 with Password and Bearer 【公式サイト】OAuth2 with Password (and hashing), Bearer with JWT tokens 今回の注目点はクライアント側の動きです。「FastAPI OAuth2パスワード認証 - Qiita」で記したフロー図で示したようにJWT tokenを生成し、検証するのはひたすらサーバ側です。クライアント側はtokenを単なる文字列として受け取り、保管し、リクエスト時にヘッダーに付加して送信するだけです。クライアントにとってはJWT tokenは単なる文字列にすぎません。 今回は簡単なクライアントをVueで作成しました。パスワードフローのクライアント実装の参考になればと思います。 1, プログラムとディレクトリ プログラムの詳細に入る前にディレクトリ構成について説明します。 FastAPIのプログラムファイル jwttoken.py の置いてある場所をルートディレクトリとして、その直下にstatic サブディレクトリを作成しindex.htmlとindex.jsを置きます。プログラム的にはFastAPIの静的ファイルを扱うStaticFilesを利用します。以下の2文をサーバに追加します。 jwttoken.py --- from fastapi.staticfiles import StaticFiles --- app.mount("/static", StaticFiles(directory="static"), name="static") 起動はルートディレクトリで以下のコマンドで行います。 uvicorn jwttoken:app --reload ブラウザからのアクセスは以下の通りです。 http://localhost:8000/static/index.html 2. クライアント プログラムの簡素化のためにVue.jsを使用します。ファイルはindex.htmlとindex.jsの2つです。 2-1. HTMLファイル - index.html 画面は1ページだけで、「ログイン」のLoginフォームと、「リソースにアクセス」するGet Resourceボタン2つから成ります。 ログインは、OAuth2パスワード認証の規則に従ってusername/passwordをForm bodyで送信しなければなりません。結果としてJWT tokenが返ってきます。 リソースへのアクセスは、Authorization headerが必要で、その値が「Bearer + token」の形であることが求められます。 FastAPI OAuth2パスワード認証 - Qiita index.html <html> <head> <link rel="stylesheet" href="index.css"> <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script> <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script> </head> <body> <div id="app"> <h1>Login</h1> <p><input v-model="username"></p> <p><input v-model="password"></p> <button v-on:click="doLogin">Login</button> <p>Current token = {{ token }}</p> <hr> <h1>Get Resource</h1> <button v-on:click="getMe">Get Me</button> <button v-on:click="getItems">Get Items</button> <p>Response = {{ response }}</p> </div> <script src="index.js"></script> </body> </html> 2-2. クライアント画面 少し早いですが、クライアント画面の動きをレビューしておきたいと思います。 Loginの「Current token」と、Get Resourceの「Response」の初期値が~文字列であることに注意してください。 ログイン画面で以下の入力を行います。 username=johndoe, passowrd=secret Current tokenが取得でき表示されます。Responseはまだ空のままです。 「Grt Me」ボタンをクリックします。 ちゃんとResponseが表示されました。JWT tokenは正しく作られているようです。 2-3. Vueプログラム - index.js とてもシンプルなものです。3つのメソッドから成ります。ログインのハンドラーdoLogin()、リソースアクセスのgetMe()とgetItems()の3つです。 index.js var app = new Vue({ el: '#app', data: { username: 'anonymouse', password: 'abc_123', token: '', response: '' }, methods: { doLogin: function() { console.log("doLogin:: username=", this.username, " passowrd=", this.password) const params = new URLSearchParams(); params.append('username', this.username); params.append('password', this.password); let config = { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }; axios.post('/token', params, config) .then((response) => { console.log("response.data = ", response.data) this.token = response.data.access_token }) .catch((err) => { console.log("Error = ", err) }) }, getMe: function() { let config = { headers: { Authorization: `Bearer ${this.token}` } }; axios.get('/users/me', config) .then((response) => { console.log("response.data = ", response.data) this.response = JSON.stringify(response.data) }) .catch((err) => { console.log("Error = ", err) this.response = JSON.stringify(err) }) }, getItems: function() { let config = { headers: { Authorization: `Bearer ${this.token}` } }; axios.get('/users/me/items', config) .then((response) => { console.log("response.data = ", response.data) this.response = JSON.stringify(response.data) }) .catch((err) => { console.log("Error = ", err) this.response = JSON.stringify(err) }) } } }) 2-3-1. ログイン username/passwordはform bodyとしてサーバに渡す必要があります。以下のコードで実現できます。 index.js const params = new URLSearchParams(); params.append('username', this.username); params.append('password', this.password); let config = { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }; axios.post('/token', params, config) 【参考サイト】Axios post method requesting with x-www-form-urlencoded content type 2-3-2. リソース取得 Authorizationヘッダーにtokenを添付します。以下のコードで実現します。 index.js let config = { headers: { Authorization: `Bearer ${this.token}` } }; axios.get('/users/me', config) 3. サーバ - jwttoken.py JWT抜きのプログラムは以下の記事にありますので、まだの方は大変申し訳ありませんが、まずそちらを読んでください。 FastAPI OAuth2パスワード認証 - Qiita これからはJWT tokenに絞って、以下の公式サイトのドキュメントをなぞることになります。 【公式サイト】OAuth2 with Password (and hashing), Bearer with JWT tokens 3-1. サーバプログラム - jwttoken.py jwttoken.py from datetime import datetime, timedelta from typing import Optional from fastapi import Depends, FastAPI, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jose import JWTError, jwt from passlib.context import CryptContext from pydantic import BaseModel from fastapi.staticfiles import StaticFiles # to get a string like this run: # openssl rand -hex 32 SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES = 30 fake_users_db = { "johndoe": { "username": "johndoe", "full_name": "John Doe", "email": "johndoe@example.com", "hashed_password": "$2b$12$EixZaYVK1fsbw1ZfbX3OXePaWxn96p36WQoeG6Lruj3vjPGga31lW", "disabled": False, } } class Token(BaseModel): access_token: str token_type: str class TokenData(BaseModel): username: Optional[str] = None class User(BaseModel): username: str email: Optional[str] = None full_name: Optional[str] = None disabled: Optional[bool] = None class UserInDB(User): hashed_password: str pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token") app = FastAPI() app.mount("/static", StaticFiles(directory="static"), name="static") def verify_password(plain_password, hashed_password): return pwd_context.verify(plain_password, hashed_password) def get_password_hash(password): return pwd_context.hash(password) def get_user(db, username: str): if username in db: user_dict = db[username] return UserInDB(**user_dict) def authenticate_user(fake_db, username: str, password: str): user = get_user(fake_db, username) if not user: return False if not verify_password(password, user.hashed_password): return False return user def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): to_encode = data.copy() if expires_delta: expire = datetime.utcnow() + expires_delta else: expire = datetime.utcnow() + timedelta(minutes=15) to_encode.update({"exp": expire}) encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) return encoded_jwt async def get_current_user(token: str = Depends(oauth2_scheme)): credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", headers={"WWW-Authenticate": "Bearer"}, ) try: payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) print(f'### token = {token}, payload = {payload}') username: str = payload.get("sub") if username is None: raise credentials_exception token_data = TokenData(username=username) except JWTError: raise credentials_exception user = get_user(fake_users_db, username=token_data.username) if user is None: raise credentials_exception return user async def get_current_active_user(current_user: User = Depends(get_current_user)): if current_user.disabled: raise HTTPException(status_code=400, detail="Inactive user") return current_user @app.post("/token", response_model=Token) async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()): user = authenticate_user(fake_users_db, form_data.username, form_data.password) if not user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Incorrect username or password", headers={"WWW-Authenticate": "Bearer"}, ) access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES) access_token = create_access_token( data={"sub": user.username}, expires_delta=access_token_expires ) return {"access_token": access_token, "token_type": "bearer"} @app.get("/users/me/", response_model=User) async def read_users_me(current_user: User = Depends(get_current_active_user)): return current_user @app.get("/users/me/items/") async def read_own_items(current_user: User = Depends(get_current_active_user)): return [{"item_id": "Foo", "owner": current_user.username}] 3-1. PythonでJWT - python-jose pythonでJWTを扱うためにpython-joseをインストールします。 pip install "python-jose[cryptography]" python-joseの利用方法は以下の通り。 >>> from jose import jwt >>> token = jwt.encode({'key': 'value'}, 'secret', algorithm='HS256') u'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJrZXkiOiJ2YWx1ZSJ9.FG-8UppwHaFp1LgRYQQeS6EDQF7_6-bMFegNucHjmWg' >>> jwt.decode(token, 'secret', algorithms=['HS256']) {u'key': u'value'} python-jose - GIT secretは以下のコマンドで取得できます。 openssl rand -hex 32 566fad6d8df44eef2c4be2727b6693153bf61f6bae30b3e8e4fb5697e1953d0a JWTに関係のある個所を抜粋すると以下のようになります。 jwttoken.py from jose import JWTError, jwt --- # to get a string like this run: # openssl rand -hex 32 SECRET_KEY = "09d25e094faa6ca2556c818166b7a9563b93f7099f6f0f4caa6cf63b88e8d3e7" ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_MINUTES = 30 --- def create_access_token(data: dict, expires_delta: Optional[timedelta] = None): to_encode = data.copy() if expires_delta: expire = datetime.utcnow() + expires_delta else: expire = datetime.utcnow() + timedelta(minutes=15) to_encode.update({"exp": expire}) encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) return encoded_jwt --- access_token = create_access_token( data={"sub": user.username}, expires_delta=access_token_expires ) decodeの結果をプリントしているので確かめてみます。 jwttoke.py async def get_current_user(token: str = Depends(oauth2_scheme)): credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials", headers={"WWW-Authenticate": "Bearer"}, ) try: payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM]) print(f'### token = {token}, payload = {payload}') コンソールには以下のプリント出力があります。正しいですね。 ### token = eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJqb2huZG9lIiwiZXhwIjoxNjM3ODIwNjU5fQ.TU5EI6Y8bfshkT1h4hY7IW3z6_cx2mkF-yaqq3j2KhE, payload = {'sub': 'johndoe', 'exp': 1637820659} 3-2. Hash を使った passwords の検証 - passlib password は平文では保存されず Hash(暗号)化されて保存されます。ここではpasslibを使ってHash化を行います。 pip install "passlib[bcrypt]" passlibに関係しているところを抜粋しています。ここではDBに保存されているパスワード hashed_password は既にハッシュ化されていると仮定しているので、ログイン時に送られてきた平文パスワードとverify関数で比較しています。 jwttoken.py from passlib.context import CryptContext --- pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto") --- def verify_password(plain_password, hashed_password): return pwd_context.verify(plain_password, hashed_password) 今回は以上です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Herokuにdashアプリをデプロイする

全体の流れ herokuアカウント取得 heroku cliインストール python仮想環境構築 プロジェクトディレクトリに必要なファイルを作成 app.py, Prockfile, requirements.txt, .gitignore heroku及びgitコマンドでデプロイ 実行環境 windows10 wsl2 Ubuntu20.04 conda 4.10.3 事前準備 gitインストール Git - Installing Git herokuのアカウントを取得 https://www.heroku.com/ heroku cliをinstall The Heroku CLI | Heroku Dev Center wsl2では以下を実行 wsl $ curl https://cli-assets.heroku.com/install.sh | sh heroku cliのインストール確認 wsl $ heroku --version heroku/7.59.2 linux-x64 node-v12.21.0 condaでpython仮想環境を準備 wsl $ conda create -n heroku_test python=3.10 $ conda activate heroku_test heroku login wsl $ heroku login heroku: Press any key to open up the browser to login or q to exit: Dashアプリの作成 プロジェクトディレクトリ作成 wsl $ mkdir dash_app_example $ cd dash_app_example モジュールインストール wsl $ pip install dash $ pip install plotly $ pip install gunicorn プロジェクトディレクトリに以下のファイルを準備 app.py Prockfile requirements.txt .gitignore app.py app.py import os import dash import dash_core_components as dcc import dash_html_components as html external_stylesheets = ['https://codepen.io/chriddyp/pen/bWLwgP.css'] app = dash.Dash(__name__, external_stylesheets=external_stylesheets) server = app.server app.layout = html.Div([ html.H2('Hello World'), dcc.Dropdown( id='dropdown', options=[{'label': i, 'value': i} for i in ['LA', 'NYC', 'MTL']], value='LA' ), html.Div(id='display-value') ]) @app.callback(dash.dependencies.Output('display-value', 'children'), [dash.dependencies.Input('dropdown', 'value')]) def display_value(value): return 'You have selected "{}"'.format(value) if __name__ == '__main__': app.run_server(debug=True) .gitignore .gitignore venv *.pyc .DS_Store .env Procfile Procfile web: gunicorn app:server requirements.txtを作成 wsl $ pip freeze > requirements.txt デプロイ wsl $ heroku create my-dash-app # change my-dash-app to a unique name $ git add . # add all files to git $ git commit -m 'Initial app boilerplate' $ git push heroku master # deploy code to heroku $ heroku ps:scale web=1 # run the app with a 1 heroku "dyno" 成功すると https://my-dash-app.herokuapp.com にアプリが公開される。 コードの更新 wsl $ git status # view the changes $ git add . # add all the changes $ git commit -m 'a description of the changes' $ git push heroku master 参考資料 https://dash.plotly.com/deployment
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LabelMEの使い方(セマンティックセグメンテーション用アノテーションツール)

本記事でわかること LabelMeのインストール方法、および使い方 出力ファイル(json)の画像化 LabelMeってなに? MITによって作られたアノテーションツールで、本記事ではセマンティックセグメンテーション用のアノテーションのために使っていきます。 LabelMeのインストール インストール方法は「Anaconda経由」と「venv+pip経由」の2通りを紹介します。 といっても中身は対して変わりません。お好きな方をどうぞ。 ※それぞれ、Anacondaをインストール済み、Pythonをインストール済みを前提条件としています。 ※詳細はこちらから。 Anaconda経由のインストール conda create --name=[任意の仮想環境名] python=[任意のPythonのversion] activate [任意の仮想環境名] conda install pyqt pip install labelme venv+pip経由のインストール python -m venv [任意の仮想環境名] ./[任意の仮想環境名]/Scripts/activate pip install labelme PyQt5 LabelMeの起動 以下のコードを実行すると、ウィンドウが開きます。 labelme LabelMEの使用手順 上の画像に振った番号の通りです。 ① 画像の入ったフォルダを開きます。 ② マウスでカチカチして任意の物体を囲みます。囲み終わると「クラス名」を聞かれるので、入力しましょう。 ③ 必要なら修正します。 ④ アノテーションデータを保存します。(①で指定したフォルダを確認すると○○.jsonというファイルが生成されてると思います。) ⑤ 次の画像にいきましょう。(①に戻る。) json から PNG へ 生成されたjsonファイルですが、このままではうまくアノテーションできたか確認しづらいかと思います。なので、画像化することで視覚的に確認していきましょう。以下のコードを実行してください。 labelme_json_to_dataset ○○.json すると「○○_json」というフォルダができ、その中に以下の4点が生成されます。 img.png label.png label_names.txt label_viz.png さいごに 本記事では、LabelMEを用いてセマンティックセグメンテーション用のアノテーション作業を紹介しました。 他にもインスタンスセグメンテーション用に変換もできるようなので、試してみたいところ。 それでは~(^^)/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LINE Notify + ラズパイで自宅から研究室のモニタリングをした話。

はじめに 【この記事で分かること】 LINE Notifyのインストール方法と簡単な使い方 ラズパイと専用カメラを用いた顔認識 背景 新型コロナウイルスの拡大に伴い、 日本でもリモートワークを推奨するようになってきた今日この頃。 私の研究室でも緊急措置が取られました。 なんと...研究室に出勤日?が設けられたのです。 2021年5月現在は、無事解除されました。めでたし。 この経験を経て、リモートワークに感銘を受けたボクは、ふと思ったわけです。 『研究室に誰が来たか』を自宅から知りたい。 Slackとか導入すればいいけど、みんなやりたがらないしなぁ…。 学生がたくさん来てる時間帯に研究室に行きたくない。 これらの希望を叶えるには、どうすればよいか… 『そうだっ!研究室をモニタリングすればいいのでは!?』 使ってないラズパイもあるし、なんとかなりそう...そう考えたボクは実行に移しました。 実行環境 今回実装にあたって、用いた実行環境・ガジェットは以下の通り。 RaspberryPi 3 modelB+ RaspberryPi専用カメラ Python ver3.6 OpenCV ver3.4 LINE Notify ↑こんな感じでできればいいなぁと考えてました。 実装 1. ラズパイとカメラで顔認識 まずは、ディレクトリの構成から。xmlファイルはOpenCVの該当フォルダから持ってきます。 ./ ├ imgs/ ├ haarcascade_frontalface_alt.xml └ people_detected_with_camera.py プログラムのソースコードは以下の通り。 from datetime import datetime import time import RPi.GPIO as GPIO import requests import os import cv2 import picamera import picamera.array SLEEPTIME = 5 PEOPLE_NO = 1 DIR = os.getcwd() with picamera.PiCamera() as camera: with picamera.array.PiRGBArray(camera) as stream: camera.resolution=(480, 360) camera.framerate=30 while True: camera.capture(stream, 'bgr', use_video_port=True) grayimg = cv2.cvtColor(stream.array, cv2.COLOR_BGR2GRAY) face_cascade = cv2.CascadeClassifier(os.path.join(DIR, "haarcascade_frontalface_alt.xml")) facerect = face_cascade.detectMultiScale(grayimg, scaleFactor=1.2, minNeighbors=2, minSize=(100,100)) if len(facerect)>0: img_name = os.path.join(DIR, ("imgs/people_{}.jpg".format(PEOPLE_NO))) cv2.imwrite(img_name, stream.array) print("No.{} send!".format(PEOPLE_NO)) time.sleep(SLEEPTIME) PEOPLE_NO += 1 #break cv2.imshow('camera', stream.array) key = cv2.waitKey(1) if key & 0xFF == ord('q'): print("Finish!") break stream.seek(0) stream.truncate() cv2.destoryAllWindows() OpenCVライブラリに同梱のxmlファイルを元に顔認識を行いました。 本当はDeepLearningモデルなど用いた方が精度はいいのでしょうが…。 今回は簡単に実装することがコンセプトなので後回しです。 上のソースコードを実行すると、こんな感じで ラズパイのディスプレイ上にウィンドウが出力されます。 2. LINE Notifyの導入 つぎにLINE Notifyを導入して、ラズパイで撮影した画像を 自分のLINEアカウントに送信します。 その前に、LINE Notifyに登録しなければなりません。(参考サイトはコチラ) 上記の参考サイトを参照し、順当に進めていただきますと、アクセストークンが発行されます。 これをコピーしておきます。(念のため、メモもしておきましょう。) ラズパイに戻って顔認識のソースコードを一部追記します。 下記のソースコードのACCESS_TOKENのところに 発行されたアクセストークンを入力します。 def line_notify(img_name): payload = {'message' : '人いるよ'} headers = {'Authorization' : "Bearer ACCESS_TOKEN"} files = {"imageFile":open(img_name,'rb')} requests.post('https://notify-api.line.me/api/notify', headers = headers, params = payload, files = files) line_notify(img_name) 全体のコードがコチラ。 from datetime import datetime import time import RPi.GPIO as GPIO import requests import os import cv2 import picamera import picamera.array SLEEPTIME = 5 PEOPLE_NO = 1 DIR = os.getcwd() def line_notify(img_name): payload = {'message' : '人いるよ'} headers = {'Authorization' : "Bearer ACCESS_TOKEN"} files = {"imageFile":open(img_name,'rb')} requests.post('https://notify-api.line.me/api/notify', headers = headers, params = payload, files = files) with picamera.PiCamera() as camera: with picamera.array.PiRGBArray(camera) as stream: camera.resolution=(480, 360) camera.framerate=30 while True: camera.capture(stream, 'bgr', use_video_port=True) grayimg = cv2.cvtColor(stream.array, cv2.COLOR_BGR2GRAY) face_cascade = cv2.CascadeClassifier(os.path.join(DIR, 'haarcascade_frontalface_alt.xml')) facerect = face_cascade.detectMultiScale(grayimg, scaleFactor=1.2, minNeighbors=2, minSize=(100,100)) if len(facerect)>0: img_name = os.path.join(DIR, ("imgs/people_{}.jpg".format(PEOPLE_NO))) cv2.imwrite(img_name, stream.array) line_notify(img_name) print("No.{} send!".format(PEOPLE_NO)) time.sleep(SLEEPTIME) PEOPLE_NO += 1 #break #cv2.imshow('camera', stream.array) key = cv2.waitKey(1) if key & 0xFF == ord('q'): print("Finish!") break stream.seek(0) stream.truncate() cv2.destoryAllWindows() 3. 実際に検証! それでは、ラズパイの前に立ち LINEに送信されるかの検証をします。 "ピコンッ!" うん、ちゃんと送信されています。 まずまずといったところでしょうか。 システムは完成したので、一日仕掛けてみて 他の学生もかかるか試してみます。 結果はこんな感じ。 カメラ目線をくれているものは、バッチリ撮れていますね。 また、見切れている画像も多々ありました。 フレームレートや画質に対して調整が必要なようです。 加えて、このように誰もいないのに送信されるケースもありました。 後ろの坂本龍馬さんに反応してしまったようです。 ある意味、ホラーでした。 さいごに いかがでしたでしょうか?今回は、LINE Notifyとラズパイで自宅からの研究室モニタリングシステムを実装しました。 当初はサーバーを立てて、そちらにデータ蓄積・送信する予定でしたが、よくよく考えたら、外出時にリアルタイムで見れないし、自宅に居たとしても、わざわざPCの前に行かないと確認できないのでは?と思い、急遽LINEに送るシステムにシフトしました。 現状、人が来たことは分かりますが、誰が来たかはボクが判断して初めて分かります。この性質上、自動で出勤簿をつけたり、個人に対するの出勤パターンの解析をするにはまだまだ改良が必要なことが分かりますね。 あと、当システムは双方向受信ではなく、LINE Notify側から一方的に取得画像が送られてくるだけなので、こちら側からアクセスできないのが難点。例えば、『今誰いる?』みたいにメッセージを送ったら、当日登校している学生のリストを送信してくれるとか、こういうのができないわけです。 また、認識精度の問題にも難点が見られたので、これは早急に改良する必要がありそう…。 というわけで、今回はこのあたりでお開きとしたいです。 それでは、よいAIライフを~(^^)/ 追伸 まずは坂本さんのような誤検出を減らしたかったので、(夜にずっと送られてくる…( ゚Д゚)ヒエッ 取り合えず人感センサーを取り付けて、誤検出を少なくしました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【初心者超必見】Google Colab で YOLO v3 を軽く実装してみた。(とりあえずテストのみです。学習のステップは次の記事で!)

はじめに 〜本記事で分かること〜 【Google ColabでYOLO v3をテストするやり方】 以前、他の記事を見て実装を試みたのですが、上手くいかなくて...。 「bin.bash : darknet is directory」とかエラー出るし。 ちゃんと記事の通りに従ったんですけどね〜。っていう人向けです。 実験環境 Windows10 professional python 3.6.6 TensorFlow 1.10.0 つらつらと記述しましたが、インターネットさえ繋がっていれば問題ないかと...。 今回、OSとかGPUとかほぼ関係ないので! PythonやTensorflowなどの環境もGoogle Colab上で完結していますしね。 つまり、ネット環境の整ったPCがあれば問題ないです。便利な世の中になりましたね。 実装 まず、Google Colabを開きます。こちらから、アクセスできます。もし、Googleアカウントを持っていないよ!って方は、この際なので作ってしまいましょう!3分もあればすぐ作れちゃいます! アクセスしますと、違うタブに移行します。 ここでは、下の図のようなウィンドウが開かれると思いますが 「ノートブックを新規作成」をクリックしましょう。 そして、Google Colabのトップページがこんな感じ。↓上の画像の赤枠から新しくコードを生成していきます。 すると、新しくブロックが生成されているかと思います。 ここにコードを書いていくわけですね。 因みに、このブロックを「セル」と言ったりします。 さてさて、本番はここからです。 先程生成したセルに以下のコードを打ち込んでください。 次に実行します。実行方法は 「Ctrl」+「Enter」を押す。 セルの横にある実行ボタンを押す。 「ランタイム」→「現在のセルを実行」を押す。 があります。どれでも構いません。 %%bash git clone https://github.com/pjreddie/darknet cd darknet make 実行が完了しましたら、「コード」を押して、また新しくセルを生成します。 そして以下のコードを打ち込んで下さい。打ち終わったら実行。 このセルでは、ディープラーニングにおいての必須級アイテム「重み」を入手しています。 !wget https://pjreddie.com/media/files/yolov3.weights そして、いざっ! テストへ!! 新しくセルを生成して、以下のコードを打ち込み、実行です! 詳細な説明は省きますが、以下のコードでは、 「用意された関数」「dataファイル」「cfgファイル」「weightsファイル」「テスト画像」 で構成されています。それぞれを適宜変更することで 皆さんの用意した画像でも物体検出ができてしまうわけです。 !./darknet detector test cfg/coco.data cfg/yolov3.cfg yolov3.weights data/dog.jpg 結果 ちゃんと出力されるかなぁっとワクワクしていましたが、 一向に表示される気配がありません。 失敗か?と思いきや、ちゃんと保存されていました! 上の画像のサイドバーにある橙色で囲われた「ファイル」をクリックして、 darknet → prediction.jpgの順に開いてみて下さい。 こんな画像が出力されれば、成功です! 犬と自転車、それからトラックがしっかりと検出されていますね! さいごに この記事では、Google Colabを用いてYOLO v3のテスト実装を行いました。 去年はなぜか分かりませんが、うまくいかなかったんですよね〜。 結果、途中で諦めてしまったわけですが...。 今回は事前学習済みモデルを使ったテストのみだったので、次は学習の記事でも 書いてみたいと思います。 ※あくまで私のための備忘録なので、完成度については多めに見てくださると嬉しいです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【初心者必読】VGG16を動かしたいなら、まずはColabが正解です。

〜本記事でわかること〜 ・VGG16の実装方法 1.はじめに 「わたしの備忘録」 兼 「初心者向け」の内容です。 ・Deep Learningって分かんないけど、とにかく動かしたい! ・原理とかは後回し、実装方法だけ知りたい! って方は、ぜひ読んでみてください! (Qiitaの旧アカウントから持ってきました…) 2.動作環境 動作環境は以下の通り。 ・Windows 10 ・Google Colab ・TensorFlow ver.2.3 今回はGoogle Colabにて コーディングしていくので、 OSとかは特に関係ないです。 ネット環境だけ整ってれば、とりあえずオーケー! 便利な時代になりました。 3.前準備 本記事で取り上げるVGG16というモデルは、 深層学習の中でも「画像の分類」が得意です。 なので、まずは皆さんに 自前のデータを用意してほしいんです。 わたしはマーベル作品が大好きなので、 「キャプテンアメリカ」 「アイアンマン」 「ハルク」 「ソー」 の画像を用意しました! 画像の枚数は適当でいいのですが、 手始めに各50枚ほど用意してみましょう。 用意できましたら、 VGG16が学習しやすいように フォルダを作っていきます。 というわけで、 以下のようにフォルダを作ってください。 image/ ├ train/ │ ├ captain/ │ ├ ironman/ │ ├ hulk/ │ └ thor/ │ ├ valid/ │ ├ captain/ │ ├ ironman/ │ ├ hulk/ │ └ thor/ │ └ test/ ├ captain/ ├ ironman/ ├ hulk/ └ thor/ そうしましたら、 「train」・「valid」・「test」フォルダの 各「captain」・「ironman」・「hulk」・「thor」フォルダに 画像を入れていきます。 各ヒーローごとに50枚あるので、 「train」に30枚、「valid」に10枚、「test」に10枚 入れていきます。 なので、全体の画像配置は train:150枚 valid: 50枚 test : 50枚 になりますね。 前準備はこれで終了。 4.実装 4−1 まずは、Google Driveへ Google Colabでコーディングしていくのですが そのためにも、まずGoogle Driveへ移動します。 みなさん、現代っ子のはずなので、 Googleアカウントは、さすがに持ってますよね?? (無ければこの際に作っちゃいましょ!) Googleアカウントにログインできましたら、 Google Driveへアクセス。 先程作った「image」フォルダをアップロードします。 4−2 実際にコードを書いてみよう 現時点では、おそらくGoogle Colabが インストールされていないと思うので、 下に示した図のようにインストールしていきます。 4−3 学習開始! それでは、学習していきましょう。 まずは、Google DriveとGoogle Colabを接続します。 from google.colab import drive drive.mount('/content/drive') そして、VGG16のモデルを作成していきます。 import matplotlib import numpy as np %matplotlib inline from tensorflow.python.keras.callbacks import TensorBoard from tensorflow.python.keras.applications.vgg16 import VGG16 vgg16 = VGG16(include_top=False, input_shape=(224, 224, 3), weights='imagenet') クラスの設定をします。 ここは皆さんの用意したデータによって変えてください。 import random classes = ['captain', 'ironman', 'hulk', 'thor'] モデルの生成とコンパイルをします。 compileのパラメータに「loss」や「optimizer」や「metrics」がありますが これらをイジることで、解きたいタスクを変えたり、学習を収束させやすくできます。 今回は以下の値で学習させていきましょう。 from tensorflow.python.keras.models import Sequential, Model from tensorflow.python.keras.layers import Dense, Dropout, Flatten, GlobalAveragePooling2D from tensorflow.keras.optimizers import SGD def build_transfer_model(vgg16): model = Sequential(vgg16.layers) for layer in model.layers[:15]: layer.trainable = False model.add(Flatten()) model.add(Dense(256, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(len(classes), activation='softmax')) return model model = build_transfer_model(vgg16) model.compile(loss='categorical_crossentropy', optimizer=SGD(lr=1e-5, momentum=0.9), metrics=['accuracy'] ) ジェネレータとイテレータを生成します。 カンタンに言うと、画像の拡張やスケール変換をしています。 この処理を挟むことで、1枚の画像からでも複数枚の画像を生成することができるのです。 人間の目で見れば、「ただ左右反転したり、斜めにしてみた画像じゃん?」ってなるんですが、 学習モデルにとっては、ピクセル単位で処理していくため、違う画像に見えるわけですね。 from tensorflow.python.keras.preprocessing.image import ImageDataGenerator from tensorflow.python.keras.applications.vgg16 import preprocess_input idg_train = ImageDataGenerator(rescale=1/255., shear_range=0.1, zoom_range=0.1, horizontal_flip=True, preprocessing_function=preprocess_input ) idg_valid = ImageDataGenerator(rescale=1/255.) img_itr_train = idg_train.flow_from_directory(directory='/content/drive/My Drive/image/train/', target_size=(224, 224), color_mode='rgb', classes=classes, batch_size=1, class_mode='categorical', shuffle=True ) img_itr_validation = idg_valid.flow_from_directory(directory='/content/drive/My Drive/image/valid/', target_size=(224, 224), color_mode='rgb', classes=classes, batch_size=1, class_mode='categorical', shuffle=True ) モデル保存用のディレクトリの準備をします。 import os from datetime import datetime model_dir = os.path.join('/content/drive/My Drive/image/', datetime.now().strftime('%y%m%d_%H%M') ) os.makedirs(model_dir, exist_ok = True) print('model_dir:', model_dir) dir_weights = os.path.join(model_dir, 'weights') os.makedirs(dir_weights, exist_ok = True) 学習の途中経過を保存したり、保存方法を設定します。 from tensorflow.python.keras.callbacks import CSVLogger, ModelCheckpoint import math file_name='vgg16_fine' batch_size_train=1 batch_size_validation=1 steps_per_epoch=math.ceil(img_itr_train.samples/batch_size_train ) validation_steps=math.ceil(img_itr_validation.samples/batch_size_validation ) cp_filepath = os.path.join(dir_weights, 'ep_{epoch:02d}_ls_{loss:.1f}.h5') cp = ModelCheckpoint(cp_filepath, monitor='loss', verbose=0, save_best_only=False, save_weights_only=True, mode='auto', save_freq=5 ) csv_filepath = os.path.join(model_dir, 'loss.csv') csv = CSVLogger(csv_filepath, append=True) そして、ついに学習です。「epochs」を50に設定しているので、学習回数は50回です。 ※厳密には学習回数とepochは同じ意味ではないのですが、 今回は支障がないので名前を統一しています。 hist=model.fit_generator( img_itr_train, steps_per_epoch=steps_per_epoch, epochs=50, verbose=1, validation_data=img_itr_validation, validation_steps=validation_steps, shuffle=True, callbacks=[cp, csv] ) model.save(file_name+'.h5') コーディングが終わったので、 上からソースコードを実行していきます。 以下が途中経過の一例になります。 これが「Epoch 50/50」まで続きます。 それが学習終了の合図です。 Epoch 1/50 80/80 [==============================] - 18s 228ms/step - loss: 1.2106 - accuracy: 0.5000 - val_loss: 1.2738 - val_accuracy: 0.3500 Epoch 2/50 80/80 [==============================] - 22s 276ms/step - loss: 1.0407 - accuracy: 0.5875 - val_loss: 1.1765 - val_accuracy: 0.5000 Epoch 3/50 80/80 [==============================] - 34s 419ms/step - loss: 0.9078 - accuracy: 0.6375 - val_loss: 1.2011 - val_accuracy: 0.5500 Epoch 4/50 80/80 [==============================] - 31s 387ms/step - loss: 0.9747 - accuracy: 0.5625 - val_loss: 1.2541 - val_accuracy: 0.5000 4−4 結果は・・・?? さて、学習は終了しましたが、 まだ不完全です。 それもそのはず。 大学生に例えれば「講義」を受けて「課題」を 解いたにすぎないからです。 ある一定の評価(=単位)をもらうには、 「試験(テスト)」が残っています。 といわけで、次のコードを実行しましょう。 import matplotlib.pyplot as plt from tensorflow.python.keras.preprocessing.image import load_img, img_to_array, array_to_img idg_test = ImageDataGenerator(rescale=1.0/255) img_itr_test = idg_test.flow_from_directory(directory='/content/drive/My Drive/image/test/', target_size=(224,224), batch_size=1, class_mode='categorical', shuffle=True ) score=model.evaluate_generator(img_itr_test) print('\n test loss:',score[0]) print('\n test_acc:',score[1]) plt.figure(figsize=(10,15)) for i in range(4): files=os.listdir('/content/drive/My Drive/image/test/' + classes[i] + '/') for j in range(5): temp_img=load_img('/content/drive/My Drive/image/test/' + classes[i] + '/' + files[j], target_size=(224,224)) plt.subplot(4,5,i*5+j+1) plt.imshow(temp_img) temp_img_array=img_to_array(temp_img) temp_img_array=temp_img_array.astype('float32')/255.0 temp_img_array=temp_img_array.reshape((1,224,224,3)) img_pred=model.predict(temp_img_array) plt.title(str(classes[np.argmax(img_pred)]) + '\nPred:' + str(math.floor(np.max(img_pred)*100)) + "%") plt.xticks([]),plt.yticks([]) plt.show() 結果は、こんな感じ。 test loss: 1.0708633661270142 test_acc: 0.550000011920929 全体の精度にして、55%となりました。 まぁ、まずまずといったところでしょうか。 それではもっと詳しく見ていきます。 各画像の予測結果はこんな感じ。 うん、アイアンマンの正答率がいい感じ。 アイアンマンが好きな私としては嬉しい結果です〜♪ 画像枚数を増やしたり、パラメータや学習回数などをいじれば もっと精度は向上するでしょうが・・・ 今日のところはお開きとしたいです。 5.おわりに いかがでしたか?? 原理などは一切説明しませんでしたが、 少しでもAIに関して興味をもってもらえると嬉しいです。 本記事では、VGG16の実装方法を紹介しましたが、 実はこのモデル、結構古いんですよね・・・。 (2015年に論文が執筆されています。詳しくはこちら。) 今は新しく精度の高いモデルも たくさん出ているので、興味がある方は ぜひ試してみてください! では、よいAIライフを〜 ^^
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プログラミング初学者がAtCoder茶色に到達するまでの学習ステップ

自己紹介 当記事を閲覧してくださり誠にありがとうございます。 都内の私立大学経営学部に在籍しているさんちょと申します。 プログラミングを始めて半年ちょいのプログラミング初学者(Python)です。 はじめに 当記事はプログラミング初学者がAtCoderに登録して茶色(レーティング562)に到達するまでに行った学習ステップを簡単に記録したものとなっております。 AtCoderとは アルゴリズムに関する問題をプログラミングによって解き、解いた問題数や時間を競い合う競技プログラミングのコンテストを開催する国内最大級のサイト ユーザーはコンテストの結果に応じてサイト内でレーティングされ、レーティングに応じてランク(色)が付されます。 レーティング ランク(色) ユーザー分布 2800- 赤 上位0.2% 2400-2799 燈 上位0.6% 2000-2399 黄 上位2% 1600-1999 青 上位5% 1200-1599 水 上位10% 800-1199 緑 上位20% 400-799 茶 上位35% -399 灰 上位100% ※ユーザー分布は2021/11/25時点 学習ステップ 1. ABC(AtCoder Beginner Contest)に参加してみる 重要なことはAtCoderを体験してみることです。 ユーザー登録 AtCoder内で最も簡易的なコンテストABCに参加 現在の自分の実力を確かめてみましょう! 2. AtCoder Problemsで過去問 他ジャンルの学習法と同様にAtCoderでも過去問練習が重要です。 AtCoder ProblemsでUser IDを入力 UserのRecommendation機能をチェック →自分のレベル感に適した問題が自動的に提示 EasyとModerateに取り組んでみましょう! 目安は1日3時間取り組んでEasy5問、Moderate2問程度 ※Difficultは余力のある場合のみ取り組んでみて下さい。 3. 解法の記録 競技プログラミングで重要なことの1つとしてアルゴリズムの理解度があります。 アルゴリズムの理解度を高めるために過去問やコンテストで解けなかった問題の解法(自分の解法と正解の解法)を逐一まとめておきましょう! 例 @Anti-Division ABC137C問題 ◎A以上B以下の整数でCでもDでも割り切れない数の個数 ・自分の回答 ①BをCで割った切り捨て数-AをCで割った切り上げ数 ②BをDで割った切り捨て数-AをDで割った切り上げ数 if B>C*Dの場合 ③BをC×Dで割った切り捨て数-AをC×Dで割った切り上げ数 回答:(B-A)-①-②+③ else 回答:(B-A)-①-② ・正解 問題の条件を満たすB以下の整数の個数-問題の条件を満たす(A-1)以下の整数の個数 問題の条件を満たすx以下の整数の個数は以下の式 x-(x//C)-(x//D)+(x//lcm(C, D)) ※自分がわかる程度で簡潔に書くことがポイント! 4. 最後に 毎週開催されるABCに必ず参加 ※頻繁に参加することでレーティング伸び率が向上 A問題とB問題はできる限り早く解く C問題は時間をかけて必ず解く まずはA,B,C問題を必ず解けるようになりましょう!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

sklearnのPipeline,(SelectFromModel, GridSearchCV)の利用法、実装を覚書

scikit-learnで特徴量選択や予測モデルはPipelineを用いて、連結して処理ができる ただ、Pipelineは連結処理を隠してしまうのでどう処理されるのかチェックした内容を覚書 まずPipelineの前提として Pipeline(model_1, model_2, model_3, model_4)と様々なモデルを渡すことができるが、 ・最終モデル(この例ではmodel_4)は.fitのみが必要 ・途中のモデル(model_1,2,3)は.fitと.transformが必要 この前提を満たしていれば様々なpipelineの渡し方が可能。 基本形 selector = SelectFromModel(Lasso()) estimator = RandomForestRegressor() pipe = Pipeline([('selector', selector), ('estimator', estimator)]) pipe.fit(X,y) pipe.fit時にはSelectFromModelのtransformが呼ばれ、 特徴量選択されたX_selected がestimatorに渡される PipelineをGridSearchCVで最適化 selector = SelectFromModel(Lasso()) estimator = RandomForestRegressor() pipe = Pipeline([('selector', selector), ('estimator', estimator)]) parameters = {'estimator__n_estimators':[10,100,200]} gscv = GridSearchCV(pipe, parameters) gscv.fit(X,y) GridSearchCVに渡すパラメータ名は'estimator_n_estimators'のように <モデル名>_<パラメータ名>と変わることに注意 更に、GridSearchCVをpipelineの中に入れるトリッキーな使い方もできる # GridSearchCVをpipelineの中に入れる selector = SelectFromModel(Lasso()) estimator = RandomForestRegressor() parameters = {'n_estimators':[10,100,200]} searcher = GridSearchCV(estimator, parameters ) pipe = Pipeline([('selector', selector), ('searcher', searcher)]) pipe.fit(X,y) pipe.predict(X_test) この場合、 pipe.predict時にはGridSearchCVで最適化されたRandomForestが利用され、 predict時に再度GridSearchされることはない* *この実装部分は未確認。 ただし、SelectFromModelの選択される特徴量はfit時とpredict時で変わりうるので sklearnのオリジナル実装のままでは使いにくいかもしれない。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Django】一つのviewに対して二つのurlを対応させる

はじめに Djangoプロジェクトを開発する際に「このページのURLのパターンが二つ欲しいな」と思う場面がありました.自分なりにやってみたところ現状うまくいってるのでご紹介します. どんな状況で複数のurlを対応させる必要があるのか? 「そもそも,そんな機能を実装することあるの?」と思う方もいらっしゃると思います.なので,私がこの機能を実装したいなと考えたきっかけとなる状況を簡単に共有します. 私が開発していたプロジェクトではアプリケーション上に地図を表示するもの(以下,地図表示ページ)がありました.そのページでは,対象の人などの位置情報を更新する必要があり,私は定期的にこのページを自動リロードさせることでその更新を実現していました. プロジェクト内の別ページからこの地図表示ページにアクセスする場合は表示する地図座標は設定してあるデフォルト値で問題ないのですが,地図表示ページがリロードされたときにも毎回デフォルト座標に戻されてしまうと、「うざい,,」って感じますよね。 そこでリロードされた場合は,リロード前に閲覧してた座標を使って地図を表示してやろうと考えました. 要件定義 上記の状況から要件をまとめると,こうなります. 1.プロジェクト内の別ページから地図表示ページにアクセスした場合には,設定されたデフォルト座標を基に地図を表示する. 2.地図表示ページがリロードされた場合は,リロード前の地図座標を基に地図を表示する. 実装手順 この記事の内容を取り入れようと考えて下さる方に向けて実装手順を記載致します. 今回は地図の表示に「地図の拡大率」と「表示する中心座標」が必要なので,この二つの要素を表示するまでを目標としましょう. 環境 macOS Catalina 10.15.7 Python: 3.8.5 Django: 3.2.8 前提条件 この記事では,「myproject」プロジェクト内の「example」アプリケーションでの開発を想定してます. 1.「example」アプリケーションを作成する $ python manage.py startapp example 2.設定ファイルにexampleアプリケーションを追加する ※設定ディレクトリ名はconfigであると仮定してます myproject/config/settings.py INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', + 'example.apps.ExampleConfig', # アプリケーション追加 … ] 3.exampleアプリケーションのURLを定義する diff urlpatterns = [ … + path('example/', include('example.urls')), … ] 4.Viewを定義する ここで,Viewを定義する際にURLパラメータをkwargs.get('<URLパラメータ>')で取得します.このとき,URLパラメータの有無で処理を変えることで一つのviewを複数のURLに対応させます. myproject/example/views.py from django.views.generic import TemplateView class Index(TemplateView): template_name = 'index.html' # 「地図の拡大率」と「表示する中心座標」のデフォルト値をグローバル変数に定義しておく(数字自体に特に意味はないです) global def_map_zoom def_map_zoom = 20 global def_center_lonlat def_center_lonlat = [139.7673068, 35.6809591] def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # 呼び出しURLによって処理を変更 try: # URL内に変数値がある場合はその値を入力する context['map_zoom'] = int(kwargs.get('map_zoom')) context['center_lonlat'] = [float(kwargs.get('longitude')), float(kwargs.get('latitude'))] except: # URL内に変数値がない場合はデフォルト値を入力する context['map_zoom'] = def_map_zoom context['center_lonlat'] = def_center_lonlat return context 5.アプリケーション内のURLを定義する myproject/example/urls.py from django.urls import path from . import views app_name = 'example' urlpatterns = [ # 以下二つのURLは同じViewを呼び出しています path('', views.Index.as_view(), name='def_index'), path('<str:map_zoom>/<str:longitude>/<str:latitude>', views.Index.as_view(), name='index'), ] 6.Templateを作成する 今回は簡単に表示するまでが目標なので,以下のようなtemplateを作成します. myproject/example/template/index.html <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>My test page</title> </head> <body> <p>マップズーム拡散率:{{ map_zoom }}</p> <p>表示中心座標:{{ center_lonlat }}</p> </body> </html> 7.Djangoプロジェクトを起動する $ python manage.py runserver Watching for file changes with StatReloader Performing system checks... System check identified no issues (0 silenced). November 25, 2021 - 08:40:51 Django version 3.2.9, using settings 'config.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C. 確認 下記のURLにアクセスしてページ内の表示結果を確認してみてください. また,二つ目のURLのURLパラメータを変更してみて実際に適応できているかも確認してもらえるといいと思います. デフォルト値のURL http://127.0.0.1:8000/example/ URLパラメータ付きのURL http://127.0.0.1:8000/example/19/139.0000000/35.0000000 まとめ 今回の記事の内容を使うこと自体珍しいとは思いますが,できると知っているだけでもその壁に当たったときに解決までの時間が全然違ってくると思うので把握しておいて損はないかなと思います. 最後まで読んで頂きありがとうございます.今回はここで終わりです. ※ご意見や疑問点などお待ちしております! 参考文献 HTML の基本 - ウェブ開発を学ぶ - MDN Web Docs
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SIGNATEの練習問題をやってみた

コンペに参加した理由  同じ研究室の大学4年生と大学院1年生の2人で、データ分析を行う練習のために参加した。目標はあくまでも、高精度分析ではなくコードを書いて、考察をしてみるというものである。そのため、練習用に準備されているデータの分析を行なった。(国勢調査からの収入予測) 今後パート2、3、4、と続いていく予定です。この記事は分析をしてきた足跡を残す気持ちで書きます。 データの可視化(数値データだけ) ・全体の値を描画 何故かわかりませんが、ヒストグラムのyの値が小さくなってしまいました。 ・収入に応じてプロットの色を変更 キャピタルゲインとの関係が大きくありそうな予感がします。うまく、分けることができそうなデータもありますが、全てをうまく分けることができなさそうなので、目で見るだけでなく数値を出してみます。 ・相関関係のヒートマップ y(年収)との相関が強い説明変数がいくつかありますね。というよりもfnlwgt以外は相関がありそうな予感がします。0が高収入のカテゴリになっているので負の相関があるということは年収と正の相関があるということになります。 このヒートマップを見ても教育年数と年収は相関が強いことがわかります。イメージ通りです。 データの前処理 回のデータはほとんどのデータが質的変数だったので、ダミー変数にして解析を行なっていきま。 数値データは標準化か正規化をしていきます。 箱ヒゲ図を見てみるとid以外は外れ値が存在しており、正規化をすると重要な情報が潰される可能性があるので、今回は標準化を採用します。 特徴量選択 特徴量の選択として、ランフダムフォレストとロジスティック回帰を使う。 ロジスティック回帰の結果 accは0.7856265356265356、なので特徴をうまくつかめている可能性が高い。ただ、今回のデータは説明変数が多いので、どの程度説明変数を使おうか考えるために、重要度の高い順でn個説明変数をとってくる(n=5,10,15,...,105)。 重要度をヒストグラムで表示 重要度の高い説明変数から順序よくn個とってきて、nを変更させて表示してみる。 説明変数が多くなっても正答率が変わらないので最初の5個でうまく行くのではないか? 説明変数が少なくてもある程度のものが表現されていそう。 ん?縦軸のメモリがおかしい。無視お願いします。 ランダムフォレスト Grid-Searchを用いてハイパーパラメータを調整した結果、accは85.71で、いい予測ができている。 特徴量の重要度は可視化してないが、上位3つは「キャピタルゲイン」「fnlwgt」「年齢」であった。この3つの説明変数を使って、モデルを構築した。 3つの説明変数を用いたときのモデルのaccは0.8093775593775594となった。 5%下がっっているが、それでも、ロジスティク回帰の精度よりも高いのでいい。 モデルの学習 xgboost  ランダムフォレストで用いた3つの特徴量を用いて、xgboostを試した結果、accは80.18となった。ランダムフォレストで求めた精度と比較してみても、殆ど変化がなかった。なので、f1_scoreを比べてみると平均で0.88とかなりいいことから、予測モデルとしては優れていると考察できる。 kokusei_xgboost.ipynb # mod3 = xgb.XGBRegressor(max_depth = 6, learning_rate = 0.1, n_estimators=10, objective='reg:squarederror', gamma=0, min_child_weight=1, subsample=1, colsample_bytree=1) mod3 = xgb.XGBClassifier(max_depth=6, learning_rate=0.1, n_estimators=10, objective='binary:logistic',gamma=0, min_child_weight=1, subsample=1, colsample_bytree=1, random_state=42) # モデルを作成。xgb.trainにおけるparamの部分 params3 = {'max_depth': [8, 7, 6, 5, 4, 3], 'learning_rate': [0.1, 0.2, 0.3], 'gamma': [0.1, 0.2, 0.3], 'min_child_weight': [0.8, 1, 1.2], 'subsample': [1, 0.9, 0.8], 'colsample_bytree': [1, 0.9, 0.8]} gscv3 = GridSearchCV(mod3, params3, cv = 5, refit=True, scoring='accuracy', verbose = 1, n_jobs=-1) # gscvをこれからやるよっていう宣言だけ。グリッドサーチは.fitで実行される。 # n_jobs=-1にするとCPU100%で全コア並列計算。とても速い。 evallist = [(train_x, train_y)] gscv3.fit(train_x, train_y, eval_metric='logloss', eval_set=evallist, early_stopping_rounds=100) # 全データに対して学習を行う。evallistの値に対してloglossで評価を行い、100round後も変化がなければ終了。 print(gscv3.best_params_) # {'colsample_bytree': 0.9, 'gamma': 0.2, 'learning_rate': 0.3, 'max_depth': 7, 'min_child_weight': 0.8, 'subsample': 0.8} x_train, x_test, t_train, t_test = train_test_split(train_x, train_y, test_size=0.2, random_state=0) train_pred = gscv3.predict(x_train) test_pred = gscv3.predict(x_test) print('train_accuracy_score_is_{:.4f}, test_accuracy_score_is_{:.4f}'.format(met.accuracy_score(t_train, train_pred), met.accuracy_score(t_test, test_pred))) # 0.8042, 0.8018 print('train_f1_score_is_{:.4f}, test_f1_score_is_{:.4f}'.format(met.f1_score(t_train, train_pred), met.f1_score(t_test, test_pred))) # 0.8849, 0.8834 今後の課題、反省  今回の解析は1ヶ月間という短い期間だったので、精度を出せるものではありませんでしたが、解析の流れを通してモデルの結果を提出することができたのでよかったと思います。 解析手法についても、より適切なものを選択する必要があると思いました。後で気づきましたが、勾配ブーストを行う手法は、外れ値の影響を受けやすいそうです笑 今後は、もっと長期間で解析をして、精度を求められるようにコーディング力と知識をつけていきたいですね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SIGNATEの練習問題をやってみた パート1

コンペに参加した理由  同じ研究室の大学4年生と大学院1年生の2人で、データ分析を行う練習のために参加した。目標はあくまでも、高精度分析ではなくコードを書いて、考察をしてみるというものである。そのため、練習用に準備されているデータの分析を行なった。(国勢調査からの収入予測) 今後パート2、3、4、と続いていく予定です。この記事は分析をしてきた足跡を残す気持ちで書きます。 データの可視化(数値データだけ) ・全体の値を描画 何故かわかりませんが、ヒストグラムのyの値が小さくなってしまいました。 ・収入に応じてプロットの色を変更 キャピタルゲインとの関係が大きくありそうな予感がします。うまく、分けることができそうなデータもありますが、全てをうまく分けることができなさそうなので、目で見るだけでなく数値を出してみます。 ・相関関係のヒートマップ y(年収)との相関が強い説明変数がいくつかありますね。というよりもfnlwgt以外は相関がありそうな予感がします。0が高収入のカテゴリになっているので負の相関があるということは年収と正の相関があるということになります。 このヒートマップを見ても教育年数と年収は相関が強いことがわかります。イメージ通りです。 データの前処理 回のデータはほとんどのデータが質的変数だったので、ダミー変数にして解析を行なっていきま。 数値データは標準化か正規化をしていきます。 箱ヒゲ図を見てみるとid以外は外れ値が存在しており、正規化をすると重要な情報が潰される可能性があるので、今回は標準化を採用します。 特徴量選択 特徴量の選択として、ランフダムフォレストとロジスティック回帰を使う。 ロジスティック回帰の結果 accは0.7856265356265356、なので特徴をうまくつかめている可能性が高い。ただ、今回のデータは説明変数が多いので、どの程度説明変数を使おうか考えるために、重要度の高い順でn個説明変数をとってくる(n=5,10,15,...,105)。 重要度をヒストグラムで表示 重要度の高い説明変数から順序よくn個とってきて、nを変更させて表示してみる。 説明変数が多くなっても正答率が変わらないので最初の5個でうまく行くのではないか? 説明変数が少なくてもある程度のものが表現されていそう。 ん?縦軸のメモリがおかしい。無視お願いします。 ランダムフォレスト Grid-Searchを用いてハイパーパラメータを調整した結果、accは85.71で、いい予測ができている。 特徴量の重要度は可視化してないが、上位3つは「キャピタルゲイン」「fnlwgt」「年齢」であった。この3つの説明変数を使って、モデルを構築した。 3つの説明変数を用いたときのモデルのaccは0.8093775593775594となった。 5%下がっっているが、それでも、ロジスティク回帰の精度よりも高いのでいい。 モデルの学習 xgboost  ランダムフォレストで用いた3つの特徴量を用いて、xgboostを試した結果、accは80.18となった。 ランダムフォレストで求めた精度と比較してみても、殆ど変化がなかった。なので、f1_scoreを比べてみると平均で0.88とかなりいいことから、予測モデルとしては優れていると考察できる。 kokusei_xgboost.ipynb # mod3 = xgb.XGBRegressor(max_depth = 6, learning_rate = 0.1, n_estimators=10, objective='reg:squarederror', gamma=0, min_child_weight=1, subsample=1, colsample_bytree=1) mod3 = xgb.XGBClassifier(max_depth=6, learning_rate=0.1, n_estimators=10, objective='binary:logistic',gamma=0, min_child_weight=1, subsample=1, colsample_bytree=1, random_state=42) # モデルを作成。xgb.trainにおけるparamの部分 params3 = {'max_depth': [8, 7, 6, 5, 4, 3], 'learning_rate': [0.1, 0.2, 0.3], 'gamma': [0.1, 0.2, 0.3], 'min_child_weight': [0.8, 1, 1.2], 'subsample': [1, 0.9, 0.8], 'colsample_bytree': [1, 0.9, 0.8]} gscv3 = GridSearchCV(mod3, params3, cv = 5, refit=True, scoring='accuracy', verbose = 1, n_jobs=-1) # gscvをこれからやるよっていう宣言だけ。グリッドサーチは.fitで実行される。 # n_jobs=-1にするとCPU100%で全コア並列計算。とても速い。 evallist = [(train_x, train_y)] gscv3.fit(train_x, train_y, eval_metric='logloss', eval_set=evallist, early_stopping_rounds=100) # 全データに対して学習を行う。evallistの値に対してloglossで評価を行い、100round後も変化がなければ終了。 print(gscv3.best_params_) # {'colsample_bytree': 0.9, 'gamma': 0.2, 'learning_rate': 0.3, 'max_depth': 7, 'min_child_weight': 0.8, 'subsample': 0.8} x_train, x_test, t_train, t_test = train_test_split(train_x, train_y, test_size=0.2, random_state=0) train_pred = gscv3.predict(x_train) test_pred = gscv3.predict(x_test) print('train_accuracy_score_is_{:.4f}, test_accuracy_score_is_{:.4f}'.format(met.accuracy_score(t_train, train_pred), met.accuracy_score(t_test, test_pred))) # 0.8042, 0.8018 print('train_f1_score_is_{:.4f}, test_f1_score_is_{:.4f}'.format(met.f1_score(t_train, train_pred), met.f1_score(t_test, test_pred))) # 0.8849, 0.8834 今後の課題、反省  今回の解析は1ヶ月間という短い期間だったので、精度を出せるものではありませんでしたが、解析の流れを通してモデルの結果を提出することができたのでよかったと思います。 解析手法についても、より適切なものを選択する必要があると思いました。後で知りましたが、勾配ブーストを行う手法は、外れ値の影響を受けやすいそうです笑 今後は、もっと長期間で解析をして、精度を求められるようにコーディング力と知識をつけていきたいですね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GitHub Actions と cibuildwheel を使ってarm64対応 wheel をビルドする

背景 最近はデスクトップでもサーバーでもARMが躍進しています。 macOSのApple Silliconはもちろん、LinuxでもAWSのGraviton2やRaspberry PiなどでARMマシンが多くの人に使われています。WindowsのARM版も今後増えてくるかもしれません。 Python拡張モジュールのメンテナとしては、そういった環境のためにバイナリwheelを提供してあげたいところですが、ビルド環境を用意するのが大変になってしまいます。そこで役に立つのが cibuildwheel です。 cibuildwheelについて 公式サイト: cibuildwheel はCI環境上で複数の環境向けのwheelをビルドするためのツールです。現在のCIごとの対応プラットフォームは下の表の通りです。(上記公式サイトより) GitHub Actions では全てのプラットフォームがサポートされているのがわかります。 対応しているCPUアーキテクチャは次のようになります。 Windowsではx86_64とx86のみ arm64対応はまだexperimentalで、CI側がRunnerを用意するのを待つか自前でarm64版Windowsを用意する必要がある macOSではx86_64, arm64, universal2 Linuxではx86_64, x86, arm64, ppc64le s390x cibuildwheel がどうやってwheelをビルドしているか、現時点(v2.2.2)での振る舞いを簡単に説明しておきます。 Windows nuget を使って、 wheel を作りたいバージョンとアーキテクチャのPythonをインストールし、その上でwheelをビルドします。 クロスコンパイルやエミュレーションはしていないので、ARM64版のビルドにはARM64版のWindowsが必要になります。 macOS Python公式サイト (www.python.org) からPythonをダウンロードしてインストールし、その上でwheelをビルドします。 公式サイトのPythonがuniversal2バイナリになっているPython 3.8以降では、arm64版とuniversal2版のwheelをクロスコンパイルできますが、amd64版のRunnerではテストを実行できない(arm64版をエミュレーションできない)のでデフォルトでは無効になっています。 将来的に Apple Sillicon 版の Runner が提供されたときに、そちらでarm64版とuniversal2版のビルドをする予定になっています。 Linux DockerとPyPAが提供しているmanylinuxやmusllinuxなどのイメージを使ってwheelをビルドしてます。 amd64とi686以外にもqemuを使うことでaarch64(arm64)やppc64le, s390xのwheelをビルドし、テストを実行できます。 注意点 上で説明した通り、cibuildwheelはCIのRunnerが提供しているPythonではなくて自力でPythonをダウンロードして実行するようになっています。 そのため、CIが提供している標準的な方法 (GitHub Actions の setup-python など) を使う場合に比べて時間もかかりますし、外部サービス (www.python.org, nuget, Dockerイメージを配布しているRed Hatのquay.io) にも負荷をかける事になります。 amd64以外のいろいろなアーキテクチャを使えるのは魅力的ですが、 GitHub の push や pull_request といった頻繁に起動されるイベントで実行するのはお勧めしません。 msgpack の例 msgpackのwheelのビルドを、自前で書いていたスクリプトからcibuildwheelに移行してみました。この設定ファイルを解説していきます。 .github/workflows/wheel.yml name: Build Wheels on: push: branches: [main] create: プルリクをマージしたときと、タグを作成したときだけに実行するため、このような設定にしました。このファイル自体を編集している間は pull_request: を追加して、マージする直前に外しました。 jobs: build_wheels: strategy: matrix: os: [ubuntu-20.04, windows-2022, macos-10.15] runs-on: ${{ matrix.os }} name: Build wheels on ${{ matrix.os }} 各プラットフォームでwheelをビルドするために matrix の設定をしています。 CPUアーキテクチャやPythonのバージョンはcibuildwheelが面倒を見るのでmatrixにする必要はありません。 steps: - name: Checkout uses: actions/checkout@v2 - name: Set up QEMU if: runner.os == 'Linux' uses: docker/setup-qemu-action@v1 with: platforms: arm64 Linuxでarm64版のバイナリを作成したいので、Dockerでqemuを使えるようにしています。 - name: Set up Python 3.9 uses: actions/setup-python@v2 with: python-version: 3.9 cache: "pip" - name: Prepare shell: bash run: | pip install -r requirements.txt make cython Cythonを使ってコード生成している部分です。これはmsgpackがCythonを使っているためで、cibuildwheelとは関係ないです。 - name: Build uses: pypa/cibuildwheel@v2.2.2 env: CIBW_TEST_REQUIRES: "pytest" CIBW_TEST_COMMAND: "pytest {package}/test" CIBW_ARCHS_LINUX: auto aarch64 CIBW_ARCHS_MACOS: x86_64 universal2 arm64 CIBW_SKIP: pp* pypa/cibuildwheel Actionを使って cibuildwheel を実行しています。(他にはpipでcibuildwheelをインストールして実行する方法もあります) Actionを使う場合は環境変数で設定をします。 CIBW_TEST_REQUIRES は、テストを実行するために追加でインストールするパッケージです。LinuxではDockerの中でテストを実行するので、ホスト側のPythonで pip install pytest しても意味がありません。 CIBW_TEST_COMMAND はテストを実行するためのコマンドです。このコマンドが実行される時のカレントディレクトリがパッケージの場所とは限らない(特にDockerで)ので、 {package} というプレースホルダを使っています。 CIBW_ARCHS_LINUX はLinuxでビルドするCPUアーキテクチャです。デフォルトだとautoでamd64とx86だけなので、 aarch64 を追加しています。 CIBW_ARCHS_MACOS はmacOSでビルドするCPUアーキテクチャです。上でも触れた通り、amd64のRunnerだとデフォルトでamd64版しかビルドしてくれないので、 universal2 と arm64 を追加しています。 CIBW_SKIP はビルドから除外する対象をタグで指定するものです。 msgpack は PyPy で拡張モジュールを使うと逆に遅くなるのでPyPyを除外しています。 CPythonのprefixが cp で PyPy のprefixがppなので pp* でPyPyを除外しています。 この他にもいろいろな設定があります。詳細はドキュメントを参照してください。 - name: Upload Wheels uses: actions/upload-artifact@v1 with: name: Wheels path: wheelhouse 最後に、ビルドしたwheelをartifactにアップロードしています。 cibuildwheel が wheel を出力するデフォルトのディレクトリが wheelhouse になっているので、そのディレクトリをアップロード対象として指定しています。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コロナウイルスの日ごとの死者数をグラフ化

厚生労働省オープンデータの死亡者数(累積)から日々の死亡者数のグラフをgoogle colaboratoryで作成 厚生労働省のオープンデータには累積の死亡者数しかなかったので 日ごとの死者数を算出してグラフ化してみました。 データはhttps://www.mhlw.go.jp/stf/covid-19/open-data.html から「死亡者数(累積)」のcsvファイルをダウンロードして google colaboratory でグラフ化してみました。 コロナウイルスの現状把握に役立てられればと。 ダウンロードした deaths_cumulative_daily.csv をgoogle colaboratoryに読み込んでください。 numpyとpandasとmatplotlibをimport import import numpy as np import pandas as pd import matplotlib.pyplot as plt downloadした死亡者数(累積)のデータ deaths_cumulative_daily.csv を読み込み Prefecture=="ALL"で全国のデータのみにする df = pd.read_csv('/content/deaths_cumulative_daily.csv') df = df.query('Prefecture=="ALL"') Deaths(Cumulative) 列をリストとして抜き出し Todayリストを作成 Today = list(df['Deaths(Cumulative)']) Today リストの先頭に元の先頭の要素を挿入し、最後尾の要素を削除してYesterdayリストを作成 Today.insert(0,Today[0]) Today.pop() Yesterday = Today 作成したYesterdayリストを'yesterday'列としてdfに読み込み df['yesterday'] = Yesterday Deaths(Cumulative)からyesterdayを引くことで日ごとの死者数DailyDeathsを算出 df['DailyDeaths'] = df['Deaths(Cumulative)'] - df['yesterday'] Date列をdatetime型に変換 df['Date'] = pd.to_datetime(df['Date']) グラフ作成 df.plot('Date','DailyDeaths') plt.show()
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker上でのStreamlitの使用方法【Windows 10】

はじめに Windows環境で、数値計算の環境の事情(例えばcvxpyとか環境構築がめんどっちいとかの事情があります)からLinuxを使用したいことがあります。そのような場合、Dockerを用いるかと思います。しかしながら、streamlitをDockerのコンテナで実行した際、Webブラウザの見方があまり記事としてなかったので拙いながらもまとめてみます。 環境 Windows 10 Docker for Windows Python streamlit コンテナの作成 下記のコマンドを実行しコンテナを作成する。 $ docker run -it -p 8501:8501 -v <パス>:/home/jovyan/work --name unko jupyter/datascience-notebook /bin/bash Streamlitの実行 試しに下記のPythonファイルを実行することを考えます。 import streamlit as st st.title("Hello World !") ターミナルでPythonファイルを実行してみます。 $ pip install streamlit $ python -m streamlit run hello.py すると下記の結果が得られるかと思います。 それではブラウザで結果を表示してみましょう。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

データサイエンティストのインターン面談をして採用側が気になっていること。

はじめに:本稿のターゲット データサイエンティストを目指す若手エンジニアや学生向けに投稿しました いまもっとも熱い職種の一つとなっているデータサイエンティスト。 その影響もあって大学生や若手の社会人でもその道を目指す人が増えています。 私は現在インターンの採用面談をしていますが、その工程の中で、 ◎データサイエンティストはどのような仕事なのか解像度がまだ低い ◎実社会で求められているスキルと目指す側の方向性に乖離が起きている というようなことを感じましたので一度ここで振り返っておこうと思います。 データサイエンティストに求められる条件は数学だけなのか? 以下はデータサイエンティストに求められる素養を端的に表現した図になります。 ご覧の通り。求められる素養は プログラミング力、ビジネス力、数学力の3つが条件となっています。 データサイエンティストを目指している学生はほぼ皆さん数学の勉強はしっかりされています。 積極的にコンペに参加したり、そういう研究に参加したり。それ自体はとても素晴らしいことです。今後も是非継続してもらいたいものです。 しかし、気になっているのはそれの一点突破になっている人が多いことです。 私は数学ができます。なのでデータサイエンティストになりたいです。という論理構成で来たら皆さんはどう思いますか?将来は相関、因果、傾向と対策を分析したい人がイケてない論理構成している。この時点で解像度が低く、採用意欲はわきませんね。 データサイエンティストになるには数学”も”素養がないといけない。 では数学は当然としてなぜプログラミング力やビジネス力が必要なのか説明していきます。 プログラミング力が必要とされる理由①データの整形 データさえあれば分析できるという誤解 統計学上必要なデータの母数があれば、分析できると思っている方が多く、むしろそう思うほうがデフォルトだと思うのですが、ここが最初の乖離、解像度の低い原因となります。 ではなぜ分析できないのか? 例 住所記入の場合 ◎東京都新宿区西新宿2丁目8-1 ◎東京都新宿区西新宿2-8-1 ◎東京都新宿区西新宿2-8-1 ◎東京都新宿区西新宿二ー八-一 上の住所は全て東京都庁の住所になります。同じものを表現しています。そして全て正しいです。 なので住所としての機能は十分で、郵便を送る際にはどのフォーマットでもちゃんと届くでしょう。 全角数字は基本的に文字として認識されますが、郵便配達の方が読んでわかれば良いので数字だろうと文字だろうと機能します。 しかし解析や分析を行う場合、対象データにバラバラのフォーマットが混在していたら統一性がないので分析できません。 このように住所として機能することを前提として作られた住所録はそれを満たせば十分なので、分析性を考慮していません。世の中にあるデータは分析性を考慮されているもののほうが圧倒的に少ないでしょう。このような場合、分析するためにはフォーマットを統一する必要があります。 データを分析にも適した形に変更するという作業が必要になります。 どのフォーマットに統一するのが良いか(アーキテクト思考等)、いかに手早く作業(プログラミング等)するのか、今後はどういう運用にするか(運用構築等)を考えるためには技術的な考察や作業が必要となります。 大学で使用するデータはすでに整形されているものが多いと思われるので、この作業認識が希薄になりやすいと思います。分析する前にやっかいな仕事があるという認識を明示的に持ったほうが良いでしょう。 プログラミング力が必要な理由②大量のデータを分析するために必要な環境構築 データが分析できるようになったあとは・・・ こちらは広義な意味で技術力の話になります。 データを分析できる形に整形が終わったら次はデータを分析します。 何十万、何百万、ときには何千万件、それ以上の膨大なデータ量になるかもしれません。 以前はその処理に耐えられるスペックの実環境を用意できる会社でしか巨大なデータ分析はできませんでしたが、現在はAWS等を始めとしたクラウド技術を使用することにより障壁が低くなりました。 しかしクラウド環境とはいえ、高スペックの環境を構築するとコストは高くなります。 重要なデータを扱う場合(個人情報など)、セキュリティの概念も当然必要となります。 その条件はプロジェクトにより異なると思いますが、 適切な予算で、セキュアで、有益な情報を生み出す環境を構築する必要があります。実際のクラウド環境構築作業は別担当者で行ってもらうかもしれませんが、プログラムを実施する上での開発環境の構築という視点が必要になってきます。 ビジネス力が必要な理由①数字を使って読み解き、お金の概念を含めて説明する力 研究とビジネスの違いを意識しよう 当然ですがビジネスは学術ではありません。お金を稼ぐ優先度は高いです。 研究としての学術的な正しさを追い求めるわけではないので区別が必要です。 研究にお金がかかるのでスポンサーを集める等の逆引き的な商業行為も現実的には必要とわかっていますがビジネスと学術は基本的は別なものです。 学術的に価値がある研究が必ず儲かるわけではありませんし、本質的にはその必要もないです。 ですがビジネスにおいて、自分がある問題の相関や因果を見つけ、傾向と対策を仮説立て実施したい場合、その説明を数学の専門家ではない人達に説明して納得して貰う必要があります。そこには収益の概念も必要ですし、コストの概念も必要です。その概念がない限り、ビジネスとしては成立しません。 いかに良い仮説であっても、実行できなければ一生仮説のままです。それを検証する、現実に落とし込むためにはコミュケーション能力も含めて戦略性などのビジネスの概念や要因が必要になります。 授業で習ったことと違う場合もあるでしょうし、直接的には習っていないことも多々出てくるでしょう。それが当たり前で、それでも問題解決のために注力し続けることが大切です。それが実学としてインターンを経験する魅力でもあると思っています。 ビジネス力が必要な理由②数字で語るのは当たり前、それはすでにビジネスの常識である ビジネスの世界語は数字である 実社会で求められられていることと目指している人の乖離の原因の一つがこのポイントだと思います。 学生の皆さんはデータサイエンティストは解析、分析をする人、というイメージを持っている人が多いです。それもある意味正しいですが、それだけをやっている人はごく一部だと思います。 そのようなデータの解析がメインになるような業界、会社は絞られていると思われ ◎すでに膨大なデータがある ◎そのデータが分析する環境が整っている(BIツールなど導入済み) というような条件がすでに揃っている会社だと思います。 BIツールはビジネスインテリジェンスと呼ばれ、ビジネス上で必要な気づきを数学的思考やビジネスのテンプレートに則り見える化を手伝うシステムだと思ってください。 Tableuなど高度なBIツールになれば専門性のある数学の知識も必要になってきます。それを使って分析をメインで行っているデータサイエンティストの方もいるでしょう。その場合は数学の専門性が重要になってくると思いますので、数学の専門性を持っている学部(理工学部、数学科)などのほうが強いのではないでしょうか?そしてそのような募集はデータサイエンティストの中の少数あると思われます。 自分がそこを目指して数学のコンペや勉強をしている人は問題ありません。そのまま続けましょう。しかし、ただデータサイエンティストがそんなイメージだから、というだけの方は注意が必要です。 現在の実社会においてある程度のビジネススキルを持つ人であれば、簡単(場合によってはある程度の)な分析や解析は行います。目標や計画を数字で語る上で必須のスキルであるからです。 データが準備できており、ExcelのPivot機能でその説明に十分な表現ができるならそれでOKです。 言い換えればそれ以外の場合、それ以上の専門性(プログラミング、数学、ビジネス)が必要な場合でデータサイエンティストの出番となるわけです。将来的に自分の強みをどこにおくのか、そのイメージは持っておいたほうが良いでしょう。 レース場でタイムを競うのか、ボコボコの道をタフに走り抜けるか 同じレースだけど質が違う ごく一部のデータ解析をメインに行える人たちのイメージがF1のような整備されたレース場をいかに早く走り切るかのレースをしているのと同様です。道路もマシンもスタッフもお金や時間を使って整っている。あとはそれらを最大化するためにどうするかが腕の見せどころ、といった感じです。 その他の大多数の人はオフロードレースでボコボコの道を走り抜ける技術や気構えが必要となります。どこに穴が空いているかわからない、ひょっとしたらマシンが壊れるかもわからない、それでも応急処置をしつつ走り抜ける。そのような整地作業を経て次のフェーズに進むというイメージです。 現状の実社会ではオフロードのようなボコボコのデータを整形し、環境を整えたくてもなかなかうまく行かず、ようやく分析し、解析して正しいか考察する、それを繰り返すといったような泥臭い作業が多いです。決して華やかな仕事ばかりではありません。 こちらもまたインターンを実施する場合、どのような仕事が多いのかイメージのすり合わせを行ったほうがミスマッチが防げると考えています。 まとめ 最後に要点をまとめておきます。 ◎データサイエンティストには数学力、プログラミング力、ビジネス力が必要 ◎データを分析する作業の前にはデータが分析できるようにする作業が必要 ◎学術とビジネスは目指すゴールが違う ◎自分の強みはどこになるか考えよう。 ◎データサイエンティストは泥臭い作業も多い(能力としてそこが求められている) 以上のポイントを再度認識しておくようにしてください。 面接の準備として・・・ 学生の段階で数学、技術、ビジネスのすべての素養が十分にある、という人はいません。 もしいたらインターンをする必要はないでしょう。 なので、面接の準備として(これはインターンの面接に限らずですが) 自分の得意な分野、課題のある分野を自分自身で把握し、将来進みたい方向をざっくりでいいので決めておきましょう。もちろん後で進路変更しても良いでしょう。思ったのと違ったのであれば修正することも全然OKだと思います。 ですが自分の希望とミスマッチを起こさないためにその準備自体はしっかりとしておきましょう。 インターン募集中です 株式会社EXIDEAではデータサイエンティストのインターン生を募集しております。 この文面を読んで我こそは!という方はぜひ以下のURLから応募してください。 皆様の応募をお待ちしております。 Wantedlyから・・・ https://www.wantedly.com/projects/782385 01インターンから・・・ https://01intern.com/job/2745.html 補足 データサイエンティストに求められるスキルチェックリスト https://www.datascientist.or.jp/news/release20211119/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

データサイエンティストのインターン面談をして採用側が感じているズレの正体とは?

はじめに:本稿のターゲット データサイエンティストを目指す若手エンジニアや学生向けに投稿しました いまもっとも熱い職種の一つとなっているデータサイエンティスト。 その影響もあって大学生や若手の社会人でもその道を目指す人が増えています。 私は現在インターンの採用面談をしていますが、その工程の中で、 ◎データサイエンティストはどのような仕事なのか解像度がまだ低い ◎実社会で求められているスキルと目指す側の方向性に乖離が起きている というようなことを感じましたので一度ここで振り返っておこうと思います。 データサイエンティストに求められる条件は数学だけなのか? 以下はデータサイエンティストに求められる素養を端的に表現した図になります。 ご覧の通り。求められる素養は プログラミング力、ビジネス力、数学力の3つが条件となっています。 データサイエンティストを目指している学生はほぼ皆さん数学の勉強はしっかりされています。 積極的にコンペに参加したり、そういう研究に参加したり。それ自体はとても素晴らしいことです。今後も是非継続してもらいたいものです。 しかし、気になっているのはそれの一点突破になっている人が多いことです。 私は数学ができます。なのでデータサイエンティストになりたいです。という論理構成で来たら皆さんはどう思いますか?将来は相関、因果、傾向と対策を分析したい人がイケてない論理構成している。この時点で解像度が低く、採用意欲はわきませんね。 データサイエンティストになるには数学”も”素養がないといけない。 では数学は当然としてなぜプログラミング力やビジネス力が必要なのか説明していきます。 プログラミング力が必要とされる理由①データの整形 データさえあれば分析できるという誤解 統計学上必要なデータの母数があれば、分析できると思っている方が多く、むしろそう思うほうがデフォルトだと思うのですが、ここが最初の乖離、解像度の低い原因となります。 ではなぜ分析できないのか? 例 住所記入の場合 ◎東京都新宿区西新宿2丁目8-1 ◎東京都新宿区西新宿2-8-1 ◎東京都新宿区西新宿2-8-1 ◎東京都新宿区西新宿二ー八-一 上の住所は全て東京都庁の住所になります。同じものを表現しています。そして全て正しいです。 なので住所としての機能は十分で、郵便を送る際にはどのフォーマットでもちゃんと届くでしょう。 全角数字は基本的に文字として認識されますが、郵便配達の方が読んでわかれば良いので数字だろうと文字だろうと機能します。 しかし解析や分析を行う場合、対象データにバラバラのフォーマットが混在していたら統一性がないので分析できません。 このように住所として機能することを前提として作られた住所録はそれを満たせば十分なので、分析性を考慮していません。世の中にあるデータは分析性を考慮されているもののほうが圧倒的に少ないでしょう。このような場合、分析するためにはフォーマットを統一する必要があります。 データを分析にも適した形に変更するという作業が必要になります。 どのフォーマットに統一するのが良いか(アーキテクト思考等)、いかに手早く作業(プログラミング等)するのか、今後はどういう運用にするか(運用構築等)を考えるためには技術的な考察や作業が必要となります。 大学で使用するデータはすでに整形されているものが多いと思われるので、この作業認識が希薄になりやすいと思います。分析する前にやっかいな仕事があるという認識を明示的に持ったほうが良いでしょう。 プログラミング力が必要な理由②大量のデータを分析するために必要な環境構築 データが分析できるようになったあとは・・・ こちらは広義な意味で技術力の話になります。 データを分析できる形に整形が終わったら次はデータを分析します。 何十万、何百万、ときには何千万件、それ以上の膨大なデータ量になるかもしれません。 以前はその処理に耐えられるスペックの実環境を用意できる会社でしか巨大なデータ分析はできませんでしたが、現在はAWS等を始めとしたクラウド技術を使用することにより障壁が低くなりました。 しかしクラウド環境とはいえ、高スペックの環境を構築するとコストは高くなります。 重要なデータを扱う場合(個人情報など)、セキュリティの概念も当然必要となります。 その条件はプロジェクトにより異なると思いますが、 適切な予算で、セキュアで、有益な情報を生み出す環境を構築する必要があります。実際のクラウド環境構築作業は別担当者で行ってもらうかもしれませんが、プログラムを実施する上での開発環境の構築という視点が必要になってきます。 ビジネス力が必要な理由①数字を使って読み解き、お金の概念を含めて説明する力 研究とビジネスの違いを意識しよう 当然ですがビジネスは学術ではありません。お金を稼ぐ優先度は高いです。 研究としての学術的な正しさを追い求めるわけではないので区別が必要です。 研究にお金がかかるのでスポンサーを集める等の逆引き的な商業行為も現実的には必要とわかっていますがビジネスと学術は基本的は別なものです。 学術的に価値がある研究が必ず儲かるわけではありませんし、本質的にはその必要もないです。 ですがビジネスにおいて、自分がある問題の相関や因果を見つけ、傾向と対策を仮説立て実施したい場合、その説明を数学の専門家ではない人達に説明して納得して貰う必要があります。そこには収益の概念も必要ですし、コストの概念も必要です。その概念がない限り、ビジネスとしては成立しません。 いかに良い仮説であっても、実行できなければ一生仮説のままです。それを検証する、現実に落とし込むためにはコミュケーション能力も含めて戦略性などのビジネスの概念や要因が必要になります。 授業で習ったことと違う場合もあるでしょうし、直接的には習っていないことも多々出てくるでしょう。それが当たり前で、それでも問題解決のために注力し続けることが大切です。それが実学としてインターンを経験する魅力でもあると思っています。 ビジネス力が必要な理由②数字で語るのは当たり前、それはすでにビジネスの常識である ビジネスの世界語は数字である 実社会で求められられていることと目指している人の乖離の原因の一つがこのポイントだと思います。 学生の皆さんはデータサイエンティストは解析、分析をする人、というイメージを持っている人が多いです。それもある意味正しいですが、それだけをやっている人はごく一部だと思います。 そのようなデータの解析がメインになるような業界、会社は絞られていると思われ ◎すでに膨大なデータがある ◎そのデータが分析する環境が整っている(BIツールなど導入済み) というような条件がすでに揃っている会社だと思います。 BIツールはビジネスインテリジェンスと呼ばれ、ビジネス上で必要な気づきを数学的思考やビジネスのテンプレートに則り見える化を手伝うシステムだと思ってください。 Tableuなど高度なBIツールになれば専門性のある数学の知識も必要になってきます。それを使って分析をメインで行っているデータサイエンティストの方もいるでしょう。その場合は数学の専門性が重要になってくると思いますので、数学の専門性を持っている学部(理工学部、数学科)などのほうが強いのではないでしょうか?そしてそのような募集はデータサイエンティストの中の少数あると思われます。 自分がそこを目指して数学のコンペや勉強をしている人は問題ありません。そのまま続けましょう。しかし、ただデータサイエンティストがそんなイメージだから、というだけの方は注意が必要です。 現在の実社会においてある程度のビジネススキルを持つ人であれば、簡単(場合によってはある程度の)な分析や解析は行います。目標や計画を数字で語る上で必須のスキルであるからです。 データが準備できており、ExcelのPivot機能でその説明に十分な表現ができるならそれでOKです。 言い換えればそれ以外の場合、それ以上の専門性(プログラミング、数学、ビジネス)が必要な場合でデータサイエンティストの出番となるわけです。将来的に自分の強みをどこにおくのか、そのイメージは持っておいたほうが良いでしょう。 レース場でタイムを競うのか、ボコボコの道をタフに走り抜けるか 同じレースだけど質が違う ごく一部のデータ解析をメインに行える人たちのイメージがF1のような整備されたレース場をいかに早く走り切るかのレースをしているのと同様です。道路もマシンもスタッフもお金や時間を使って整っている。あとはそれらを最大化するためにどうするかが腕の見せどころ、といった感じです。 その他の大多数の人はオフロードレースでボコボコの道を走り抜ける技術や気構えが必要となります。どこに穴が空いているかわからない、ひょっとしたらマシンが壊れるかもわからない、それでも応急処置をしつつ走り抜ける。そのような整地作業を経て次のフェーズに進むというイメージです。 現状の実社会ではオフロードのようなボコボコのデータを整形し、環境を整えたくてもなかなかうまく行かず、ようやく分析し、解析して正しいか考察する、それを繰り返すといったような泥臭い作業が多いです。決して華やかな仕事ばかりではありません。 こちらもまたインターンを実施する場合、どのような仕事が多いのかイメージのすり合わせを行ったほうがミスマッチが防げると考えています。 まとめ 最後に要点をまとめておきます。 ◎データサイエンティストには数学力、プログラミング力、ビジネス力が必要 ◎データを分析する作業の前にはデータが分析できるようにする作業が必要 ◎学術とビジネスは目指すゴールが違う ◎自分の強みはどこになるか考えよう。 ◎データサイエンティストは泥臭い作業も多い(能力としてそこが求められている) 以上のポイントを再度認識しておくようにしてください。 面接の準備として・・・ 学生の段階で数学、技術、ビジネスのすべての素養が十分にある、という人はいません。 もしいたらインターンをする必要はないでしょう。 なので、面接の準備として(これはインターンの面接に限らずですが) 自分の得意な分野、課題のある分野を自分自身で把握し、将来進みたい方向をざっくりでいいので決めておきましょう。もちろん後で進路変更しても良いでしょう。思ったのと違ったのであれば修正することも全然OKだと思います。 ですが自分の希望とミスマッチを起こさないためにその準備自体はしっかりとしておきましょう。 インターン募集中です 株式会社EXIDEAではデータサイエンティストのインターン生を募集しております。 この文面を読んで我こそは!という方はぜひ以下のURLから応募してください。 皆様の応募をお待ちしております。 Wantedlyから・・・ https://www.wantedly.com/projects/782385 01インターンから・・・ https://01intern.com/job/2745.html 補足 データサイエンティストに求められるスキルチェックリスト https://www.datascientist.or.jp/news/release20211119/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

実社会でデータサイエンティストに求められているもの。

はじめに:本稿のターゲット データサイエンティストを目指す若手エンジニアや学生向けに投稿しました いまもっとも熱い職種の一つとなっているデータサイエンティスト。 その影響もあって大学生や若手の社会人でもその道を目指す人が増えています。 私は現在インターンの採用面談をしていますが、その工程の中で、 ◎データサイエンティストはどのような仕事なのか解像度がまだ低い ◎実社会で求められているスキルと目指す側の方向性に乖離が起きている というようなことを感じましたので一度ここで振り返っておこうと思います。 データサイエンティストに求められる条件は数学だけなのか? 以下はデータサイエンティストに求められる素養を端的に表現した図になります。 ご覧の通り。求められる素養は プログラミング力、ビジネス力、数学力の3つが条件となっています。 データサイエンティストを目指している学生はほぼ皆さん数学の勉強はしっかりされています。 積極的にコンペに参加したり、そういう研究に参加したり。それ自体はとても素晴らしいことです。今後も是非継続してもらいたいものです。 しかし、気になっているのはそれの一点突破になっている人が多いことです。 私は数学ができます。なのでデータサイエンティストになりたいです。という論理構成で来たら皆さんはどう思いますか?将来は相関、因果、傾向と対策を分析したい人がイケてない論理構成している。この時点で解像度が低く、採用意欲はわきませんね。 データサイエンティストになるには数学”も”素養がないといけない。 では数学は当然としてなぜプログラミング力やビジネス力が必要なのか説明していきます。 プログラミング力が必要とされる理由①データの整形 データさえあれば分析できるという誤解 統計学上必要なデータの母数があれば、分析できると思っている方が多く、むしろそう思うほうがデフォルトだと思うのですが、ここが最初の乖離、解像度の低い原因となります。 ではなぜ分析できないのか? 例 住所記入の場合 ◎東京都新宿区西新宿2丁目8-1 ◎東京都新宿区西新宿2-8-1 ◎東京都新宿区西新宿2-8-1 ◎東京都新宿区西新宿二ー八-一 上の住所は全て東京都庁の住所になります。同じものを表現しています。そして全て正しいです。 なので住所としての機能は十分で、郵便を送る際にはどのフォーマットでもちゃんと届くでしょう。 全角数字は基本的に文字として認識されますが、郵便配達の方が読んでわかれば良いので数字だろうと文字だろうと機能します。 しかし解析や分析を行う場合、対象データにバラバラのフォーマットが混在していたら統一性がないので分析できません。 このように住所として機能することを前提として作られた住所録はそれを満たせば十分なので、分析性を考慮していません。世の中にあるデータは分析性を考慮されているもののほうが圧倒的に少ないでしょう。このような場合、分析するためにはフォーマットを統一する必要があります。 データを分析にも適した形に変更するという作業が必要になります。 どのフォーマットに統一するのが良いか(アーキテクト思考等)、いかに手早く作業(プログラミング等)するのか、今後はどういう運用にするか(運用構築等)を考えるためには技術的な考察や作業が必要となります。 大学で使用するデータはすでに整形されているものが多いと思われるので、この作業認識が希薄になりやすいと思います。分析する前にやっかいな仕事があるという認識を明示的に持ったほうが良いでしょう。 プログラミング力が必要な理由②大量のデータを分析するために必要な環境構築 データが分析できるようになったあとは・・・ こちらは広義な意味で技術力の話になります。 データを分析できる形に整形が終わったら次はデータを分析します。 何十万、何百万、ときには何千万件、それ以上の膨大なデータ量になるかもしれません。 以前はその処理に耐えられるスペックの実環境を用意できる会社でしか巨大なデータ分析はできませんでしたが、現在はAWS等を始めとしたクラウド技術を使用することにより障壁が低くなりました。 しかしクラウド環境とはいえ、高スペックの環境を構築するとコストは高くなります。 重要なデータを扱う場合(個人情報など)、セキュリティの概念も当然必要となります。 その条件はプロジェクトにより異なると思いますが、 適切な予算で、セキュアで、有益な情報を生み出す環境を構築する必要があります。実際のクラウド環境構築作業は別担当者で行ってもらうかもしれませんが、プログラムを実施する上での開発環境の構築という視点が必要になってきます。 ビジネス力が必要な理由①数字を使って読み解き、お金の概念を含めて説明する力 研究とビジネスの違いを意識しよう 当然ですがビジネスは学術ではありません。お金を稼ぐ優先度は高いです。 研究としての学術的な正しさを追い求めるわけではないので区別が必要です。 研究にお金がかかるのでスポンサーを集める等の逆引き的な商業行為も現実的には必要とわかっていますがビジネスと学術は基本的は別なものです。 学術的に価値がある研究が必ず儲かるわけではありませんし、本質的にはその必要もないです。 ですがビジネスにおいて、自分がある問題の相関や因果を見つけ、傾向と対策を仮説立て実施したい場合、その説明を数学の専門家ではない人達に説明して納得して貰う必要があります。そこには収益の概念も必要ですし、コストの概念も必要です。その概念がない限り、ビジネスとしては成立しません。 いかに良い仮説であっても、実行できなければ一生仮説のままです。それを検証する、現実に落とし込むためにはコミュケーション能力も含めて戦略性などのビジネスの概念や要因が必要になります。 授業で習ったことと違う場合もあるでしょうし、直接的には習っていないことも多々出てくるでしょう。それが当たり前で、それでも問題解決のために注力し続けることが大切です。それが実学としてインターンを経験する魅力でもあると思っています。 ビジネス力が必要な理由②数字で語るのは当たり前、それはすでにビジネスの常識である ビジネスの世界語は数字である 実社会で求められられていることと目指している人の乖離の原因の一つがこのポイントだと思います。 学生の皆さんはデータサイエンティストは解析、分析をする人、というイメージを持っている人が多いです。それもある意味正しいですが、それだけをやっている人はごく一部だと思います。 そのようなデータの解析がメインになるような業界、会社は絞られていると思われ ◎すでに膨大なデータがある ◎そのデータが分析する環境が整っている(BIツールなど導入済み) というような条件がすでに揃っている会社だと思います。 BIツールはビジネスインテリジェンスと呼ばれ、ビジネス上で必要な気づきを数学的思考やビジネスのテンプレートに則り見える化を手伝うシステムだと思ってください。 Tableuなど高度なBIツールになれば専門性のある数学の知識も必要になってきます。それを使って分析をメインで行っているデータサイエンティストの方もいるでしょう。その場合は数学の専門性が重要になってくると思いますので、数学の専門性を持っている学部(理工学部、数学科)などのほうが強いのではないでしょうか?そしてそのような募集はデータサイエンティストの中の少数あると思われます。 自分がそこを目指して数学のコンペや勉強をしている人は問題ありません。そのまま続けましょう。しかし、ただデータサイエンティストがそんなイメージだから、というだけの方は注意が必要です。 現在の実社会においてある程度のビジネススキルを持つ人であれば、簡単(場合によってはある程度の)な分析や解析は行います。目標や計画を数字で語る上で必須のスキルであるからです。 データが準備できており、ExcelのPivot機能でその説明に十分な表現ができるならそれでOKです。 言い換えればそれ以外の場合、それ以上の専門性(プログラミング、数学、ビジネス)が必要な場合でデータサイエンティストの出番となるわけです。将来的に自分の強みをどこにおくのか、そのイメージは持っておいたほうが良いでしょう。 レース場でタイムを競うのか、ボコボコの道をタフに走り抜けるか 同じレースだけど質が違う ごく一部のデータ解析をメインに行える人たちのイメージがF1のような整備されたレース場をいかに早く走り切るかのレースをしているのと同様です。道路もマシンもスタッフもお金や時間を使って整っている。あとはそれらを最大化するためにどうするかが腕の見せどころ、といった感じです。 その他の大多数の人はオフロードレースでボコボコの道を走り抜ける技術や気構えが必要となります。どこに穴が空いているかわからない、ひょっとしたらマシンが壊れるかもわからない、それでも応急処置をしつつ走り抜ける。そのような整地作業を経て次のフェーズに進むというイメージです。 現状の実社会ではオフロードのようなボコボコのデータを整形し、環境を整えたくてもなかなかうまく行かず、ようやく分析し、解析して正しいか考察する、それを繰り返すといったような泥臭い作業が多いです。決して華やかな仕事ばかりではありません。 こちらもまたインターンを実施する場合、どのような仕事が多いのかイメージのすり合わせを行ったほうがミスマッチが防げると考えています。 まとめ 最後に要点をまとめておきます。 ◎データサイエンティストには数学力、プログラミング力、ビジネス力が必要 ◎データを分析する作業の前にはデータが分析できるようにする作業が必要 ◎学術とビジネスは目指すゴールが違う ◎自分の強みはどこになるか考えよう。 ◎データサイエンティストは泥臭い作業も多い(能力としてそこが求められている) 以上のポイントを再度認識しておくようにしてください。 面接の準備として・・・ 学生の段階で数学、技術、ビジネスのすべての素養が十分にある、という人はいません。 もしいたらインターンをする必要はないでしょう。 なので、面接の準備として(これはインターンの面接に限らずですが) 自分の得意な分野、課題のある分野を自分自身で把握し、将来進みたい方向をざっくりでいいので決めておきましょう。もちろん後で進路変更しても良いでしょう。思ったのと違ったのであれば修正することも全然OKだと思います。 ですが自分の希望とミスマッチを起こさないためにその準備自体はしっかりとしておきましょう。 インターン募集中です 株式会社EXIDEAではデータサイエンティストのインターン生を募集しております。 この文面を読んで我こそは!という方はぜひ以下のURLから応募してください。 皆様の応募をお待ちしております。 Wantedlyから・・・ https://www.wantedly.com/projects/782385 01インターンから・・・ https://01intern.com/job/2745.html 補足 データサイエンティストに求められるスキルチェックリスト https://www.datascientist.or.jp/news/release20211119/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pythonで認証・CRUD無しの簡易APIサーバを作る方法

Pythonで本格的なAPIサーバを作ろうとすると「Django REST Framework」が真っ先に思い浮かぶと思いますが、簡易的にAPIレスポンスが欲しい時もあると思います。 ここでは、ローカルホスト上でPythonから、認証・CRUD無しでhttpレスポンスを返す方法を2つ紹介します。 注意事項 下記方法ではCSRFの対策を行なっていません。 本番環境で使用する際には、他の方法で正しい(想定したサイトの想定したユーザーから受け取った)リクエストかどうかを検証する必要があります。 Python WSGI を使う方法 一番簡易的に使えるのは、Pythonの標準インターフェイスであるWSGI(Web Server Gateway Interface)を使う方法です。 WSGIの詳細について、調べれば詳しい記載が出てくると思いますが、今回は簡単にPOSTされたデータを返すAPIサーバを例に挙げます。 test_api.py from wsgiref.simple_server import make_server import json def app(environ, start_response): # POST dataの取得 query = environ['wsgi.input'].read(int(environ.get('CONTENT_LENGTH', 0))).decode('utf-8') # レスポンスヘッダの作成 status = "200 OK" headers = [ ("Content-type", "application/json; charset=utf-8"), ("Access-Control-Allow-Origin", "*"), ] if query == "": # POSTが空だった時の処理 response_json = {"message": "Data not sent."} else: # JSONをPythonの辞書型に変換 loaded_query = json.loads(query) # JSONの中身を記述 response_json = { "message": "this is response data!", "query_data": loaded_query, } start_response(status, headers) return [json.dumps(response_json).encode("utf-8")] with make_server("", 8000, app) as httpd: print("Serving on port 8000...") httpd.serve_forever() 一つのターミナルでサーバを起動します。 shell-1 $ python test_api.py >> Serving on port 8000... 上とは別のターミナルを起動し、挙動を確認します。 shell-2 $ curl -X POST -H "Content-TyGET application/json" -d '{"data":"hoge"}' localhost:8000 >> {"message": "This is response data!", "query_data": {"data": "hoge"}} これでWGISを利用した、簡易的なAPIサーバの完成です。 Djangoを使う方法 PythonのWebフレームワークであるDjangoを使い、APIレスポンスを返す views.py を作成することで実現することもできます。 WSGIを直接操作した場合に比べて、環境構築が必要ですが、DjangoがWSGIをラップしてくれているので、データ操作が簡単なメリットがあります。 またDjangoの場合、デフォルトでCSRFの検証を行うため、APIのレスポンスサーバとしてこれを無効にする処理を書かないと、エラーになってしまうので注意が必要です。 shell $ mkdir 作業フォルダ $ cd 作業フォルダ $ django-admin startproject config . $ python manage.py startapp api config/urls.py from django.contrib import admin from django.urls import path, include #"include"を追加 urlpatterns = [ path('admin/', admin.site.urls), path('api/', include('api.urls')), #追加 ] 下記ファイルを追加 api/urls.py from django.urls import path from . import views app_name = 'api' urlpatterns = [ path('', views.index, name='api'), ] 下記ファイルを編集 api/views.py from django.views.decorators.csrf import csrf_exempt from django.http.response import JsonResponse import json @csrf_exempt def index(request): # GET時の処理 if request.method == 'GET': return JsonResponse({"message": "This is GET respons."}) # POST dataの取得 if request.body == b"": return JsonResponse({"message": "Data not sent."}) query = request.body.decode("utf-8") # JSONをPythonの辞書型に変換 loaded_query = json.loads(query) # JSONの中身を記述 response_json = { "message": "This is response data!", "query_data": loaded_query, } # JSONに変換して戻す return JsonResponse(response_json) 一つのターミナルでサーバを起動します。 shell-1 $ python manage.py runserver >> Django version 3.x.x, using settings 'config.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CONTROL-C. 上とは別のターミナルを起動し、挙動を確認します。 shell-2 $ curl -X POST -H "Content-TyGET application/json" -d '{"data":"foo"}' localhost:8000/api/ >> {"message": "This is response data!", "query_data": {"data": "foo"}} これでDjangoを利用した、簡易的なAPIサーバの完成です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

個人開発でクラス設計をしたらほんの少しだけオブジェクト指向のメリットがわかった

はじめに この記事はオブジェクト指向や多態性(ポリモーフィズム)、継承がちょっとわかった気になった自分自身のアウトプットのために書いた記事です。 現時点でチームで開発を行った経験はなく、実務で触ったコードはというとVBAくらいで、JavaとJavaScriptを新入社員研修で習ったくらいの人間が書いています。 初学者の方は私の記事を見てわかった気にならず、書籍やほかの技術記事なども読んでオブジェクト指向の理解に勤めてください。 間違っていることなどあれば、いつでもコメントでガンガン突っ込んでください。勉強して修正します。 動機 個人開発のアウトプットを目に見える形で残しておきたかったため。 転職してすぐの新人研修でオブジェクト指向のことは学習したけれど、1年半ほど経って内容をほとんど忘れてしまったため。 疑問 個人開発でゴミ出しの日をお知らせしてくれるLINE Botを作ろう!と思い立ち、要件定義→外部設計まで行いました。 開発経験がほとんどない私にとって内部設計のクラス設計はかなり難易度が高かったため、オブジェクト指向を一度学びなおす必要性を感じました。 その中で見つけたのが↓のQiita記事です。(オブジェクト指向に対しての理解に自信がない方は絶対読んだ方が良い内容です) 【オブジェクト指向と10年戦ってわかったこと】 https://qiita.com/tutinoco/items/6952b01e5fc38914ec4e この記事を一通り読み、理解したつもりで作ったのが以下のクラス図です。 ここで私の頭に1つの疑問が浮かびました。 『あれ?このクラス、ひとまとめにした方が効率良いのでは?』 つまりはこういうことです。 インターフェースを継承せず、すべてをクラスメソッドとして実装しています。 ただ、これではダメなのですね。これでは多態性(ポリモーフィズム)を扱えていません。 オブジェクト指向のメリットの一つが多態性(ポリモーフィズム)です。 これは、クラスを呼び出すプログラムがインスタンスの中身を意識することなくクラスメソッドやインスタンスメソッドを扱うことができ、メンテナンス性を高めることができるのがメリットです。 解決 なぜこれではダメなのか、何が多態性(ポリモーフィズム)に対して不都合なのか、pythonコードで説明します。 ※LINE Botにメッセージを送るための処理を書くと複雑化してしまうため、今回はprintで代用しています。 #パターン1 すべてクラスメソッドに記述した場合 class send_message: address_sample = '\"沖縄県那覇市泉崎1丁目\"のように、都道府県、市区町村、何丁目か、まで教えてください!' where_address = 'どちらにお住まいですか?' change_where = 'どちらに変更されますか?' def frend_add_message(self): print '友達登録いただき、誠にありがとうございます!私は登録された住所に応じて毎朝7時半にゴミの情報をお送りするための、自動応答サービスです!まずは住所登録から始めましょう~' + self.where_address + self.address_sample def address_unregistered_message(self): print '住所が登録されていません!まず住所登録を行いましょう!'+ self.where_address + self.address_sample def address_change_message(self): print self.change_where + self.address_sample x = send_message() x.frend_add_message() x.address_unregistered_message() x.address_change_message() 出力結果: 友達登録いただき、誠にありがとうございます!私は登録された住所に応じて毎朝7時半にゴミの情報をお送りするための、自動応答サービスです!まずは住所登録から始めましょう~どちらにお住まいですか?"沖縄県那覇市泉崎1丁目"のように、都道府県、市区町村、何丁目か、まで教えてください! 住所が登録されていません!まず住所登録を行いましょう!どちらにお住まいですか?"沖縄県那覇市泉崎1丁目"のように、都道府県、市区町村、何丁目か、まで教えてください! どちらに変更されますか?"沖縄県那覇市泉崎1丁目"のように、都道府県、市区町村、何丁目か、まで教えてください! #パターン2 インターフェースを使って多態性(ポリモーフィズム)を意識した実装を行った場合 import abc class message(metaclass=abc.ABCMeta): address_sample = '\"沖縄県那覇市泉崎1丁目\"のように、都道府県、市区町村、何丁目か、まで教えてください!' where_address = 'どちらにお住まいですか?' change_where = 'どちらに変更されますか?' @abc.abstractmethod def send_message(self): pass class frend_add_message(message): def send_message(self): print('友達登録いただき、誠にありがとうございます!私は登録された住所に応じて毎朝7時半にゴミの情報をお送りするための、自動応答サービスです!まずは住所登録から始めましょう~' + self.where_address + self.address_sample) class address_unregistered_message(message): def send_message(self): print('住所が登録されていません!まず住所登録を行いましょう!'+ self.where_address + self.address_sample) class address_change_message(message): def send_message(self): print(self.change_where + self.address_sample) x = frend_add_message() y = address_unregistered_message() z = address_change_message() x.send_message() y.send_message() z.send_message() 出力結果: 友達登録いただき、誠にありがとうございます!私は登録された住所に応じて毎朝7時半にゴミの情報をお送りするための、自動応答サービスです!まずは住所登録から始めましょう~どちらにお住まいですか?"沖縄県那覇市泉崎1丁目"のように、都道府県、市区町村、何丁目か、まで教えてください! 住所が登録されていません!まず住所登録を行いましょう!どちらにお住まいですか?"沖縄県那覇市泉崎1丁目"のように、都道府県、市区町村、何丁目か、まで教えてください! どちらに変更されますか?"沖縄県那覇市泉崎1丁目"のように、都道府県、市区町村、何丁目か、まで教えてください! こうやって各メッセージを1回ずつ呼び出すプログラムを作る場合は、パターン1を作る方が都合が良く思えるかもしれません。 しかし、プログラムというものは基本的に1度作っただけで終わりになるものではなく、必要になったタイミングで都度拡張されていくものです。 パターン1の実装の場合、例えばx.frend_message()で出力を行っているところが10数個あり、そのすべてをx.address_unregistered_message()に変更したい場合、キーワード検索を行って検索に一致した場所を置換する作業が必要になってきますが、呼び出し先のファイルが分かれていたり、確認するコードの漏れがあった場合バグにつながりますし、そもそもそんな作業はかなり面倒です。 しかしパターン2の場合、インスタンスを設定している箇所 x = frend_add_message()を x = address_unregistered_message() に変更するだけで、呼び出しは x.send_message() から変わらないため、上記の作業は行わず、そして漏れも出さずに変更することができます。 そして、多態性(ポリモーフィズム)とはまた違いますがパターン2の場合、インターフェースを継承することで、指定のメソッドを必ずオーバーライドする強制力が働きます。 messageを継承したクラスは必ずメッセージを送ることを強制され、メッセージを送るメソッドをオーバーライドしないインスタンスを作成しようとすると、エラーを吐きます。 これが【オブジェクト指向と10年戦ってわかったこと】でも書かれている 継承は、親クラスから機能を受け継ぐためのものではなく、継承の本質は、交換可能なパーツを作成するために共通点を「規格」としてまとめ上げられるインターフェイスなのです。 の意味だと理解しています。 (実際は戻り値がなしであれば良いので、なんでも処理を書けてしまうが、send_message()というクラスメソッドをオーバーライドすることは強制できます。send_message()にメッセージを送る、以外の処理を書くプログラマーは居ないこととします。) まとめると 変更や修正をなるべく少なく抑えることができること インターフェースの継承によって継承先に「規格」を強制することができること 以上2つが、私の理解したオブジェクト指向のメリットです。 最後に 『あれ?このクラス、ひとまとめにした方が効率良いのでは?』という疑問から、オブジェクト指向を理解するための糸口を掴み、ここまで学習することができました。 今まではオブジェクト指向をなんとなく使っていて、何がメリットなのかがわからない。という状態だったので良いきっかけとなりました。 これから個人開発を行うにあたって、『ここはもっとこうした方が良いのでは?』→調べる→理解する→Qiitaにアウトプットする、という流れを意識して進めていきます。 フォローやLGTMを頂けるとこれからアウトプットするためのモチベーションにもなるため、もし差し支えなければよろしくお願いいたします。 それではここまでお読みいただき、ありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

なんでもナイトコアにする

ナイトコアとは  原曲のテンポを高速化させ、場合によっては意図的にピッチも上げて作られた、リミックスを指す音楽ジャンルである ナイトコア 出典: フリー百科事典『ウィキペディア(Wikipedia)』 ナイトコアにする とりあえず早くする import pydub from pydub import AudioSegment path = "xxxxxxx.mp3" base_sound = AudioSegment.from_file(path, format="mp3") base_sound = base_sound.speedup(playback_speed=1.5, crossfade=0) base_sound.export("nightcore.mp3", format="mp3") おしまい 音を高くするとかも多分すぐできるでしょ 今後の展開 youtubeのURLを貼ると音源がナイトコアになるようなやつ作る もっとBPM上げてGainも上げてガバキックを乗せてなんでもガバにする 目指すは ボタン一つで君もアニクラDJになれるセットを作る
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

いろいろな言語でAPIコールするよ!

導入 webAPIの叩き方を各言語でまとめました。 後で見返す用です。 2021年11月23日時点:Postリクエスト送信 json リクエストのサンプルパラメータ sample_endpoint = "http://localhost:8888/sample" sample_parameter = { "title": "トマトスープ", "making_time": "15分", "serves": "5人", "ingredients": "玉ねぎ, トマト, スパイス, 水", "cost": "450" } Curl curl --location --request POST 'http://localhost:8888/recipes' \ --header 'Content-Type: application/json' \ --data-raw '{ "title": "トマトスープ", "making_time": "15分", "serves": "5人", "ingredients": "玉ねぎ, トマト, スパイス, 水", "cost": "450" }' Go package main import ( "fmt" "strings" "net/http" "io/ioutil" ) func main() { url := "http://localhost:8888/recipes" method := "POST" payload := strings.NewReader(`{ "title": "トマトスープ", "making_time": "15分", "serves": "5人", "ingredients": "玉ねぎ, トマト, スパイス, 水", "cost": "450" }`) client := &http.Client { } req, err := http.NewRequest(method, url, payload) if err != nil { fmt.Println(err) return } req.Header.Add("Content-Type", "application/json") res, err := client.Do(req) if err != nil { fmt.Println(err) return } defer res.Body.Close() body, err := ioutil.ReadAll(res.Body) if err != nil { fmt.Println(err) return } fmt.Println(string(body)) } php <?php require_once 'HTTP/Request2.php'; $request = new HTTP_Request2(); $request->setUrl('http://localhost:8888/recipes'); $request->setMethod(HTTP_Request2::METHOD_POST); $request->setConfig(array( 'follow_redirects' => TRUE )); $request->setHeader(array( 'Content-Type' => 'application/json' )); $request->setBody('{\n "title": "トマトスープ",\n "making_time": "15分",\n "serves": "5人",\n "ingredients": "玉ねぎ, トマト, スパイス, 水",\n "cost": "450"\n}'); try { $response = $request->send(); if ($response->getStatus() == 200) { echo $response->getBody(); } else { echo 'Unexpected HTTP status: ' . $response->getStatus() . ' ' . $response->getReasonPhrase(); } } catch(HTTP_Request2_Exception $e) { echo 'Error: ' . $e->getMessage(); } python import requests import json url = "http://localhost:8888/recipes" payload = json.dumps({ "title": "トマトスープ", "making_time": "15分", "serves": "5人", "ingredients": "玉ねぎ, トマト, スパイス, 水", "cost": "450" }) headers = { 'Content-Type': 'application/json' } response = requests.request("POST", url, headers=headers, data=payload) print(response.text) これから getパラメータの記述方法なども追記していく
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Raspberry Pi Zeroでイルミネーションする

この記事について クリスマスなので、Raspberry Pi Zeroでイルミネーションしてみました コード import RPi.GPIO as GPIO import time Led_red_pin = 17 Led_green_pin = 27 Led_blue_pin = 4 GPIO.setmode(GPIO.BCM) GPIO.setup(Led_red_pin, GPIO.OUT) GPIO.setup(Led_green_pin, GPIO.OUT) GPIO.setup(Led_blue_pin, GPIO.OUT) def main(): try: while True: blinking_led(Led_red_pin, 3) blinking_led(Led_green_pin, 3) blinking_led(Led_blue_pin, 3) blinking_all_led(3) except KeyboardInterrupt: GPIO.cleanup() def blinking_led(pin, count): for i in range(count): GPIO.output(pin, GPIO.HIGH) time.sleep(0.1) GPIO.output(pin, GPIO.LOW) time.sleep(0.1) def blinking_all_led(count): for i in range(count): GPIO.output(Led_red_pin, GPIO.HIGH) GPIO.output(Led_green_pin, GPIO.HIGH) GPIO.output(Led_blue_pin, GPIO.HIGH) time.sleep(0.1) GPIO.output(Led_red_pin, GPIO.LOW) GPIO.output(Led_green_pin, GPIO.LOW) GPIO.output(Led_blue_pin, GPIO.LOW) time.sleep(0.1) if __name__ == '__main__': main() 詳しい説明 GPIOを指定するおまじないです 今回は使用するGPIOを変数で指定しています Led_red_pin = 17 Led_green_pin = 27 Led_blue_pin = 4 GPIO.setmode(GPIO.BCM) GPIO.setup(Led_red_pin, GPIO.OUT) GPIO.setup(Led_green_pin, GPIO.OUT) GPIO.setup(Led_blue_pin, GPIO.OUT) main関数で点灯させる関数をループさせます Ctl + cでループを停止し、GPIOの設定をクリアします def main(): try: while True: blinking_led(Led_red_pin, 3) blinking_led(Led_green_pin, 3) blinking_led(Led_blue_pin, 3) blinking_all_led(3) except KeyboardInterrupt: GPIO.cleanup() 指定したGPIOを点滅させる関数 def blinking_led(pin, count): for i in range(count): GPIO.output(pin, GPIO.HIGH) time.sleep(0.1) GPIO.output(pin, GPIO.LOW) time.sleep(0.1) すべてのGPIOを点滅させる関数 def blinking_all_led(count): for i in range(count): GPIO.output(Led_red_pin, GPIO.HIGH) GPIO.output(Led_green_pin, GPIO.HIGH) GPIO.output(Led_blue_pin, GPIO.HIGH) time.sleep(0.1) GPIO.output(Led_red_pin, GPIO.LOW) GPIO.output(Led_green_pin, GPIO.LOW) GPIO.output(Led_blue_pin, GPIO.LOW) time.sleep(0.1) Pythonでmain関数を呼び出すおまじない if __name__ == '__main__': main() 動かしてみる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ゼロから作るDeep Learning 自然言語処理編を理解する Chap1

概要 本記事では,ゼロから作るDeep Learning 自然言語処理編を理解することを目指し,その箇所の引用・自分なりに大事だなと思ったこと・感想などをまとめていきます.(知識不足な所も多々ありますが,温かい目で見守って頂ければと思います) 「ゼロから作る」というだけあって,プログラムを組みながら学んでいきたいと思いますが,公開されていないプログラムまで引用するのは避け,本記事では割愛させて頂きます. 一方で,Githubに公開されているプログラムもある為,こちらdeep-learning-from-scratch-2は参考になるかと思います! 本記事では,書籍における1章を扱います. Chap1 - ニューラルネットワークの復習(pp.1-55) 1.1 数学とPythonの復習 基本的な数学の知識確認とNumpy, Pandas等のPythonライブラリの復習を行います.特に気になった点をまとめていきます ・テンソルとは? ベクトルや行列を拡張してN次元の数の集まりと考えることができます.これは一般的にテンソルと呼ばれます (from p2) ここで本書で初めてテンソルという概念を扱うわけですが,NNのみならず,機械学習全般で頻出の概念になる為,この際にしっかりと理解してみたいと思います. テンソルと合わせて考えたいものが,スカラー,ベクトル,行列になります. スカラーとは,0次元の配列,ベクトルとは,1次元の配列,行列とは,2次元の配列で次元が上がっていきますが,これらは全てテンソルの一部になります. どういうことかと言いますと,スカラーは0階のテンソル,ベクトルは1階のテンソル,行列は2階のテンソル・・・のように表されます. まとめると,テンソルとはスカラー,ベクトル,行列といった考えを包括する概念になります. ・Numpyにおけるブロードキャストとは? 10というスカラ値が2×2の行列に拡張されて,そのあとで要素ごとの演算が行われます.この賢い機能はブロードキャストと呼ばれます (from p5) 実際には行列に変換されて演算が行われているという点に注目ですね ・行列の積 行列の積などの計算では,行列の形状に注目し,その推移を見ていくことが重要です (from p8) これはその通りですね.ニューラルネットでは,各層で次元が推移していくので,今いる層において次元がどうなっているのかは確実に抑えておきたいところです. 1.2 ニューラルネット(NN)の推論 入力からどういった計算を経て出力に至るのかがまとめられています. NNの推論の流れを抑えること,それをどうやって実装するのかを理解することがゴールになります. ・ミニバッチとは? NNの分野では,複数のサンプルデータ ー これを「ミニバッチ」と呼びます ー に対して一斉に推論や学習を行います (from p11) 全体のデータ数をNとした時に,k個(1<k<N)のサンプルデータを入力すること ミニバッチを用いて学習を行うことをミニバッチ学習と呼び,ミニバッチ学習以外の学習法として,バッチ学習, オンライン学習などがあります. ・活性化関数について 全結合層による変換は「線形」な変換です.これに「非線形」な効果を与えるのが活性化関数です (from p12) NNがなぜ注目されるかというと,他の線形モデル(回帰など)とは異なり,非線形な活性化関数を用いることで表現できるパターンが無数にある為です.活性化関数の中には,入力として実数を受け取り,0~1の実数を返すという特徴がある,Sigmoid関数や,-1~-1の実数を返しその結果を確率として解釈できる,Softmax関数などがあります. ・順伝播と逆伝播について NNの推論で行う処理はNNの順伝播に相当します. (中略) 後ほど,NNの学習を行いますが,そこでは順伝播とは逆方向にデータ(勾配)を伝播します.それを逆伝播と呼びます (from p14) 順伝播は,各層における重みとバイアスを元に出力の計算をします.そのため,順伝播は結果の推論時に行うものです. 一方,逆伝播は,各層の重みとバイアスを決める為に,結果側から入力側へと勾配を伝播させます.そのため,順伝播はNNの学習時に行うものです. この2つの考えはNNを扱う上で当たり前の知識ですが,違いと目的をはっきりとさせておくことが重要になります. 1.3 NNの学習 NNにおける学習が如何にして行われるのかを理解することがゴールになります.誤差逆伝播法から重みの更新の流れまで扱います. この章で最も重みが大きい単元になります. ・損失関数 NNの学習には,学習がどれだけうまくいっているかを知るための「指標」が必要になります.それは一般的に損失と呼ばれます. (中略) NNでは,損失を求めるために損失関数を使用します (from p.p 18-19) 一般的に,推論時の誤差が小さいモデルが良いモデルとされます.そういったモデルを構築する際に目指すものの1つが,学習時の損失の最小化になります.損失を求める為に損失関数が使用されます.他クラス分類では損失関数として,交差エントロピー誤差がしばしば用いられ,NNの出力ラベルと教師ラベルから求めます. ・計算グラフ 計算グラフを使えば,計算を視覚的に把握することができます (from p24) 計算グラフを構築している演算ノードには加算ノードや,乗算ノード,Repeatノードなどがあり,隠れ層ではこれらのノードを組み合わせた演算を行なっています. ・確率的勾配降下法(SGD) 重みの更新法の1つ. (中略) ランダムに選ばれたデータ(ミニバッチ)に対する勾配を用いる (from p40) 全体のデータからランダムに(確率的に)選ばれたデータに対する勾配を使って,重みを更新する手法です. 誤差逆伝播法で得られる勾配は,ある時点での重みパラメータにおいて,損失を増やす方向を指します.それとは逆方向の勾配を設定することで,損失を減らす向きのパラメータが得られるというアイデアになっています. SGD以外にも,AdaGradやMomentumといった勾配降下手法があります. 1.4 NNで問題を解く 簡単なデータセットを使って,NNの学習を行います. 損失が実際に減っているのを可視化,実感し,感動することがGoalになります ここでは,NNにおける各種パラメータをまとめてみたいと思います. ・Epoch epochは,学習の単位を表します.1epochは,学習データを全て見た時(データセットを1周した時)に相当します (from p.p 46) 1epochで全てのデータが学習に使われるんですね. ・Batch Size batch sizeは全体のデータを分割して得られたサブセットに含まれるデータ数です. ・Iterations データが少なくとも1回は参照されるのに必要な学習回数です. batch sizeが決まれば,こちらの値も自動的に決まります. e.g.) data size = 1000, batch size = 250 → iterations = 4 ・Learning Rate learning rateは,1epochで進む学習スピードを表します.大きければ,損失の減少は早いですが,最適解が必ずしも得られるとは限りません.一方で小さければ最適解が得られる可能性は高まりますが,収束に時間がかかります. 本節では,こちらの記事を参考にしました. 1.5 計算の高速化 NNの学習や推論では,多くの計算がなされ,いかにして計算を効率的に行うか,高速に行うかは永遠のテーマになっています.本節では,NNの計算時にできる工夫を理解することがGoalになります. ビット精度 Numpyでは標準で64bitの浮動小数点数が使われます.しかし,NNの推論及び学習は,32bitの浮動小数点数で問題なく(認識精度をほとんど落とすことなく)行えることが知られています (from p.p 51) NNでは,64bitほどの精度が必要とされないんですね. GPU 書籍では,NumPyと共通の機能を持ったCuPyが紹介されています. 1.6 本章のまとめ 書籍では,本章で扱ったことのまとめを行っています. Chap1のまとめと所感 自然言語処理を扱いたいと思っても,NNの知識がなければ何も始まりません. そうした中で,本書ではNNの概要,プログラムから抑えてくれたので,これまでの知識に不安があっても,復習した上でNLPの世界に入ることができるなあと思いました. (早速,名著の匂いがしています) 次節では,Chap2を扱いたいと思います! それでは,次章でお会いしましょう?
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pythonでnumpyを使わずにargsortとかargmax

Equivalent of Numpy.argsort() in basic python? - Stack Overflow range()をソートするkeyで対象のリストをインデクシングするとできます。 argsort x_list = [4, 1999, 2] i_list = sorted(range(len(x_list)), key=x_list.__getitem__) print(i_list) # [2, 0, 1] argmax x_list = [4, 1999, 2] i_max = max(range(len(x_list)), key=x_list.__getitem__) print(i_max ) # 1
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

備忘録 spreadsheet をPythonで操作する(gspread)

初心者が何とか使ってみるために色々やって なんかよくわからんけど唯一動いた()のがこの方法だったので自分用に保管しておく。 1.Google側でAPIを使う設定を済ませる いきなりPython側で操作せず、まずはGoogle側で設定する。 以下のサイトを参考にした。 https://hituji-ws.com/code/python/python-spreadsheet/  (2021.11.25閲覧)  GoogleCloudPlatformにアクセスしてAPIを有効化、その後スプレッドシート側に移動して共有の設定をする。 注意 ここでDLする.jsonファイルは後々プログラムを書くファイル(.py)と同じフォルダに保管する 2.pythonのターミナルでライブラリをインストールする 今回使いたいgspreadとoauth2clientはインストールする必要がある為、pipコマンドを用いてPythonにインストールする。 (ターミナルから) install.py pip install gspread pip install oauth2client これで下処理は完了。 3.Python側で記述する ここは勉強不足なのでよくわからないままであるがとりあえずAPIを使うために決まり文句的に書かないといけないっぽい? このサイトが死ぬほどわかりやすく説明してくれているのでこれに従って書けばおk この段階で作る.pyファイルと同じフォルダに先述の.jsonファイルがないとエラー吐いて動かない。 以下引用(自分用にコメントアウトを一部改変しています。) import gspread import json #ServiceAccountCredentials:Googleの各サービスへアクセスできるservice変数を生成します。 from oauth2client.service_account import ServiceAccountCredentials #2つのAPIを記述しないとリフレッシュトークンを3600秒毎に発行し続けなければならない(固定URL) scope = ['https://spreadsheets.google.com/feeds','https://www.googleapis.com/auth/drive'] #認証情報設定 #ダウンロードしたjsonファイル名をクレデンシャル変数に設定(秘密鍵、Pythonファイルから読み込みしやすい位置に置く) credentials = ServiceAccountCredentials.from_json_keyfile_name('.json', scope)#jsonファイルは同じフォルダ内に入れておく #OAuth2の資格情報を使用してGoogle APIにログイン gc = gspread.authorize(credentials) #スプレッドシートキーを指定してワークブックを選択(スプレッドシートURLより) workbook = gc.open_by_key('~~d/ココ/edit~~')#ここまで前提操作 #ここから自由 # シートの一覧を一次元配列に格納する worksheet_list = workbook.worksheets() #ワークシート指定 worksheet = workbook.sheet1 #読み込みはこれ(セルをダイレクトに指定) cell_value = worksheet.acell('B1').value print(cell_value) #print忘れずに 他に4つくらいのサイトの方法を試したが、どれもエラー吐いてしまった。 うまくファイルを拾えないようだったがエラーの原因もわからず。 それを解決する力などまだないので今後の課題ですね。 参考:https://tanuhack.com/library-gspread/    https://hituji-ws.com/code/python/python-spreadsheet/
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む