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

謎謎

勉強URL お勧めサイト train[train["week"]=="月"] あるデータだけ取り出せる train[["y","week"]] trainで今度はyとweekの2つのカラムを選択したい import pandas as pd import numpy as np from matplotlib import pyplot as plt %matplotlib inline train["y"].plot() 折れ線グラフ train["y"].plot.hist() ヒストグラム train[["y","week"]].boxplot(by="week") 箱ひげ図 train.isnull().any() 欠損ち train.isnull().sum() train.fillna(0) 欠損地を0で保管 train[["y","temperature"]].corr() 相関関係 train.plot.scatter(x="temperature", y="y", figsize=(5,5)) 相関係数は散布図
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DataFrameを数値型変数・カテゴリ変数で分ける方法

はじめに kaggleやデータ分析業務をやっていると、数値型(numerical)変数とカテゴリ(categorical)変数を分けて扱いたいケースが結構あるかと思います。 DataFrameを数値型変数・カテゴリ変数で分ける方法についてまとめました。 実装 今回は、みんな大好きタイタニックのデータを使用します。 kaggleのこちら↓からダウンロードできます。 まずはデータの読み込み。 import pandas as pd df = pd.read_csv('train.csv') df.head() 親の顔より見慣れたデータ。 infoでより詳細な情報を確認できます。 df.info() # <class 'pandas.core.frame.DataFrame'> # RangeIndex: 891 entries, 0 to 890 # Data columns (total 12 columns): # # Column Non-Null Count Dtype # --- ------ -------------- ----- # 0 PassengerId 891 non-null int64 # 1 Survived 891 non-null int64 # 2 Pclass 891 non-null int64 # 3 Name 891 non-null object # 4 Sex 891 non-null object # 5 Age 714 non-null float64 # 6 SibSp 891 non-null int64 # 7 Parch 891 non-null int64 # 8 Ticket 891 non-null object # 9 Fare 891 non-null float64 # 10 Cabin 204 non-null object # 11 Embarked 889 non-null object # dtypes: float64(2), int64(5), object(5) # memory usage: 83.7+ KB ここで、Dtypeは各変数のデータタイプを表しており、 int64、float64、object のいずれかの値をとっています。 objectは、主にstring値を含む変数になります。 数値型変数はint64とfloat64、カテゴリ変数はobjectの変数をそれぞれ取り出すことになります。 数値型変数の列は以下で取得できます。 num_cols = [col for col in df.columns if df[col].dtype in ['int64', 'float64']] df[num_cols] 数値型の列のみ取得できています。 同様にして、カテゴリ変数は以下で取得できます。 cat_cols = [col for col in df.columns if df[col].dtype in ['object']] df[cat_cols] キレイに分けられたところで、次は各種エンコーディングをやっていきましょう(続く)。 参考文献
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DataFrameを数値型変数・カテゴリ変数に分ける方法

はじめに kaggleやデータ分析業務をやっていると、数値型(numerical)変数とカテゴリ(categorical)変数を分けて扱いたいケースが結構あるかと思います。 DataFrameを数値型変数・カテゴリ変数で分ける方法についてまとめました。 実装 今回は、みんな大好きタイタニックのデータを使用します。 kaggleのこちら↓からダウンロードできます。 まずはデータの読み込み。 import pandas as pd df = pd.read_csv('train.csv') df.head() 親の顔より見慣れたデータ。 infoでより詳細な情報を確認できます。 df.info() # <class 'pandas.core.frame.DataFrame'> # RangeIndex: 891 entries, 0 to 890 # Data columns (total 12 columns): # # Column Non-Null Count Dtype # --- ------ -------------- ----- # 0 PassengerId 891 non-null int64 # 1 Survived 891 non-null int64 # 2 Pclass 891 non-null int64 # 3 Name 891 non-null object # 4 Sex 891 non-null object # 5 Age 714 non-null float64 # 6 SibSp 891 non-null int64 # 7 Parch 891 non-null int64 # 8 Ticket 891 non-null object # 9 Fare 891 non-null float64 # 10 Cabin 204 non-null object # 11 Embarked 889 non-null object # dtypes: float64(2), int64(5), object(5) # memory usage: 83.7+ KB ここで、Dtypeは各変数のデータタイプを表しており、 int64、float64、object のいずれかの値をとっています。 objectは、主にstring値を含む変数になります。 数値型変数はint64とfloat64、カテゴリ変数はobjectの変数をそれぞれ取り出すことになります。 数値型変数の列は以下で取得できます。 num_cols = [col for col in df.columns if df[col].dtype in ['int64', 'float64']] df[num_cols] 数値型の列のみ取得できています。 同様にして、カテゴリ変数は以下で取得できます。 cat_cols = [col for col in df.columns if df[col].dtype in ['object']] df[cat_cols] 参考文献
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DataFrameでの数値型変数・カテゴリ変数の扱い方

はじめに kaggleやデータ分析業務をやっていると、数値型(numerical)変数とカテゴリ(categorical)変数を分けて扱いたいケースがあるかと思います。 そこで、DataFrameでの数値型変数・カテゴリ変数の扱い方についてメモとしてまとめました。 DataFrameでの数値型変数・カテゴリ変数の扱い方 今回は、みんな大好きタイタニックのデータを使用します。 kaggleのこちら↓からダウンロードできます。 まずはデータの読み込み。 import pandas as pd df = pd.read_csv('train.csv') df.head() 親の顔より見慣れたデータ。 infoでより詳細な情報を確認できます。 df.info() # <class 'pandas.core.frame.DataFrame'> # RangeIndex: 891 entries, 0 to 890 # Data columns (total 12 columns): # # Column Non-Null Count Dtype # --- ------ -------------- ----- # 0 PassengerId 891 non-null int64 # 1 Survived 891 non-null int64 # 2 Pclass 891 non-null int64 # 3 Name 891 non-null object # 4 Sex 891 non-null object # 5 Age 714 non-null float64 # 6 SibSp 891 non-null int64 # 7 Parch 891 non-null int64 # 8 Ticket 891 non-null object # 9 Fare 891 non-null float64 # 10 Cabin 204 non-null object # 11 Embarked 889 non-null object # dtypes: float64(2), int64(5), object(5) # memory usage: 83.7+ KB ここで、Dtypeは各変数のデータタイプを表しており、 int64、float64、object のいずれかの値をとっています。 objectは、主にstring値を含む変数になります。 数値型変数はint64とfloat64、カテゴリ変数はobjectの変数をそれぞれ取り出すことになります。 数値型変数 数値型変数の列は以下で取得できます。 num_cols = [col for col in df.columns if df[col].dtype in ['int64', 'float64']] df[num_cols] 数値型の列のみ取得できています。 要約統計量を見るには、.describeを使用します。 df[num_cols].describe() カテゴリ変数 数値型と同様にして、カテゴリ変数は以下で取得できます。 cat_cols = [col for col in df.columns if df[col].dtype in ['object']] df[cat_cols] 要約統計量を確認してみましょう。 df[cat_cols].describe() 注釈 要約統計量とは、標本の分布の特徴を代表的に表す統計学上の値であり、統計量の一種。記述統計量、基本統計量、代表値ともいう。(Wikipedia) 参考文献
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Nmapについてまとめる THM[2]

Room: Nmap 前回のTryHackMe Linuxの基礎 THM[1] につづいて今回は3記事目。 Nmapのルームを終えたので学んだことをメモします。 TryHackMeのNmapルームを進めるのに役立つはずです。 そもそもNmapとは 指定したコンピュータのポートが開いているかどうかを調べるコマンドラインツール。 ポートが空いているかを調べるにはいくつか順番がある。 まずターゲットのコンピュータ(host)が起動しているか(up or not)どうかを調べる。(=ping scan) 次にコンピュータのポートそれぞれに対して、"お前起きてる?"と様々な方法(後解説)で問い合わせる。(=port scan) nmapはこの2つの手続きを行ってくれるやつ。 Nmapのオプション ICMP ping scan ホストが起きているかまとめて確認する。(ping sweep) nmap -sN 10.10.24.0/24 10.10.24.1~254のホストがまとめて調べられる。 pingなしでscan PingはICMPプロトコルを利用してターゲットのコンピュータが起動しているか問い合わせる。Windowsなどはセキュリティ確保のためかICMPパケット通信をすべてFirewallでブロックしています。FirewallによりPingの問い合わせが破棄されるとnmapはコンピュータがダウンしていると判断し、ポートが起きているかを調べる(=port scan)という次のステップに進めない。FirewallでICMPパケットが破棄されるコンピュータに対してポートスキャンを行う方法は、そもそもPingしないということ。-Pnオプションが役割を果たす。-PnなどでFirewallをくぐり抜けることをFirewall Evasionといったりするらしい。 nmap -Pn <ip address> TCP Connection Scan ポートスキャン方法のひとつ。-sTオプションで実行される。 ポートに対してThree way handshakeを行う。 Three way handshakeをしてこちらが何を受け取ったかでポートの状態を判断する。 SYN/ACKフラグを受け取る -> ポートは開いている RSTフラグを受け取る -> ポートは閉じている 何も受け取らない -> ポートはfiltered=Firewallがかかっている SYN scan 別称 Half-open, stealth scan。-sSオプションで実行される。 大体TCP scanとやることは同じ。 もしSYN/ACKフラグを受け取った場合、TCP scanはACKフラグをターゲットに返すが、SYN scanはRSTフラグを返す。これによりThree way handshakeが完結しなくなるため、ターゲットのポート上のアプリケーションによって通信を記録されない(このことからstealth scanといわれる)。また、ACKフラグを返さない分、TCP scanより速い。ただし、sudo permissionを要する。もしnmapがsudoで実行されたとき、nmapはデフォルトでSYN scanを実行する。それほどメジャーなスキャン方法であるということ。 SYN/ACKフラグを受け取る -> ポートは開いている RSTフラグを受け取る -> ポートは閉じている 何も反応なし -> ポートはfiltered UDP scan -sUオプション。上2つとは違いThree way handshakeやそれに相当するものを行わない。ただ問い合わせを送って、おわり。もしICMP port unreachableを受け取ったときはポートが閉じていると判断するが、それ以外の場合開いている、またはfilteredとみなす。ポートが開いている場合、何も反応がないことの確認をするために数回scanしなければならない。そのため速度が遅い。 UDPを受け取る(かなり稀) -> ポートは開いている 何も受け取らない -> ポートは開いているかfiltered ICMP port unreachableを受け取る -> ポートは閉じている NULL, FIN, Xmas scan "All three are interlinked and are used primarily as they tend to be even stealthier, relatively speaking, than a SYN "stealth" scan" - tryhackme それぞれ、-sN, -sF, -sXオプション。Firewallによって破棄されるSYNフラグをあえて送信しないことでFIrewall evasionを狙う。 何も受け取らない -> ポートは開いているかfiltered ICMP port unreachable -> filtered RSTフラグを受け取る -> ポートは閉じている ※ただしWindowsはすべてのNULL, FIN, Xmas scanにRSTを返す。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PythonでSOAPサーバにzeepを使ってアクセスする

SOAPとは SOAPとは、サーバにある関数をコールするためのプロトコル。 wsdl文書というxmlで書かれた定義ファイルがあり、そこにSOAPサーバ上でコールできるメソッドなどが書かれている。 メソッドの引数の型定義などもmessageタグで書かれている。 wsdlに配置されているタグについての説明は以下が詳しい。 WSDL:Webサービスのインターフェイス情報:Webサービスのキホン(4) - @IT wsdl文書の具体例は以下。 http://www.soapclient.com/xml/soapresponder.wsdl PythonでSOAPサーバにアクセスする zeep というSOAPクライアントのライブラリがある。 他のSOAPクライアントライブラリとの比較記事は以下。 2018年12月時点における、PythonのSOAPライブラリについて - メモ的な思考的な wsdl文書を一覧する zeepのcliでwsdl文書を読みやすく一覧できる。 # zeepがインストールされている前提。 $ python -m zeep http://www.soapclient.com/xml/soapresponder.wsdl Prefixes: xsd: http://www.w3.org/2001/XMLSchema ns0: http://www.SoapClient.com/xml/SoapResponder.xsd Global elements: Global types: xsd:anyType xsd:ENTITIES xsd:ENTITY (省略) Bindings: Soap11Binding: {http://www.SoapClient.com/xml/SoapResponder.wsdl}SoapResponderBinding Service: SoapResponder Port: SoapResponderPortType (Soap11Binding: {http://www.SoapClient.com/xml/SoapResponder.wsdl}SoapResponderBinding) Operations: Method1(bstrParam1: xsd:string, bstrParam2: xsd:string) -> bstrReturn: xsd:string # => Method1という関数があり、2つ文字列型の引数を取る。 SOAPサーバへアクセスする SOAPサーバへアクセスするコード例は以下。 import zeep wsdl = 'http://www.soapclient.com/xml/soapresponder.wsdl' client = zeep.Client(wsdl=wsdl) # zeepがwsdlを見て、Method1というメソッドを確認し、service経由でMethod1をコールできるようにしている print(client.service.Method1('hey', 'ya')) # => 'Your input parameters are hey and ya' TLS検証があるサーバにアクセスする TLS検証のあるサーバにアクセスしたい場合は、以下の方法で実現できる。 * 公式docのTransportsページ TLS verification節 from requests import Session from zeep import Client from zeep.transports import Transport session = Session() session.verify = 'path/to/my/certificate.pem' transport = Transport(session=session) client = Client( 'http://my.own.sslhost.local/service?WSDL', transport=transport) SSLクライアント認証によるアクセス制限があるサーバにアクセスする もしSSLクライアント認証によるアクセス制限のあるサーバにアクセスしたい場合は、以下の方法で実現できる。 上と似ているが、sessionのオプションであるcertの指定が増えている。 from requests import Session from zeep import Client from zeep.transports import Transport session = Session() session.verify = True session.cert = 'path/to/my/ssl_cient_cert.pem' transport = Transport(session=session) client = Client( 'http://my.own.sslhost.local/service?WSDL', transport=transport)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

RHEL8系ディストリビューションでPython 3を使う

1. RHEL8で大きく代わったPython RHEL8では、Pythonを取り巻く状況が大きく変わった。Python 3がデフォルトになり、Software Collectionsに代わってAppStreamが導入された。それ以外にも違う部分が多い。 そこで今回はRHEL8系ディストリビューションにおけるPython 3を説明する。なお、RHEL7のPython事情は以下の記事に書いている。参考になる部分も多いので興味のある方はどうぞ。 RHEL7やCentOS 7、Amazon Linux 2でPython 3を使う 1-1. 対象環境 Red Hat Enterprise Linux 8 CentOS 8 / Oracle Linux 8 / AlmaLinuxなどのRHEL8互換ディストリビューション ※ Amazon Linux 2はRHEL7に近いので、ここに書いたことは当てはまらない。 1-2. 参考情報 Red Hat Enterprise Linux 8 のPython事情 - 赤帽ブログ RHEL 8/Fedora 28で導入されたModularity - 赤帽ブログ Python in RHEL 8 - Red Hat Developer Red Hat Enterprise Linux 8 ご紹介 - Speaker Deck Red Hat Enterprise Linux 8のライフサイクルを理解する - Speaker Deck 2. RHEL8におけるPythonの変更点サマリー RHEL8におけるPythonの変更点は以下のとおり。それぞれについて説明する。また、参考資料1、3も興味があれば読んでほしい。ただし、いずれもBetaの時期に書かれたものなのでGA版と異なる部分がある。 RHEL8系ディストリビューションには次の3種類のPythonがある システムが利用するPython(Platform-Python) Python 3。デフォルトは3.6 Python 2。おもに移行用 Platform-Pythonは/usr/libexec/platform-pythonにインストールされ、ユーザーが利用することは推奨されない。そのためパスも切られていない ミニマムインストールではPython 3がインストールされない。そのためインストール環境によってはpythonやpython3を実行してもPythonが起動しない可能性がある 新しいバージョンのソフトウエアを提供する仕組みとして、これまでのSoftware Collectionsに代わってAppStreamが導入された ユーザーが使うPythonはAppStreamからインストールする RHEL6やRHEL7にあったSoftware Colletionsは提供されない 3. Pythonがインストールされていないことがある RHEL8系ディストリビューションでは、Python 3.6がデフォルトだ。しかし、pythonコマンドを実行できないことがある。このあたりの状況を説明する。 $ python -bash: python: command not found 3-1. システムが利用するPlatform-Python RHEL8系ディストリビューションには次の3種類のPythonがある。 システムが利用するPython(Platform-Python) Python 3。デフォルトは3.6 Python 2。おもに移行用 Platform-Pythonは、dnfなどシステムツールが内部的に利用するもので、必ずインストールされている。ただし、利用者が直接使うことは推奨されていないので、パスは切られていない。 $ /usr/libexec/platform-python -V Python 3.6.8 しかし、Platform-Python以外はインストールオプションによってインストールされないことがある。そのため利用環境によってはpythonやpython3コマンドを実行できない可能性がある。 こんな状況もあり得る $ python -bash: python: command not found $ python2 -bash: python2: command not found $ python3 -bash: /usr/bin/python3: No such file or directory 当然、環境によっては次のように表示されることもある。この種明かしは後ほど。 $ python -V  ★バージョンを指定しないで3.6.8になっていることに注目 Python 3.6.8 $ python2 -V Python 2.7.17 $ python3 -V Python 3.6.8 3-2. ユーザーが利用するPython ユーザーが利用可能なPythonは以下のコマンドで確認できる。出力を見ると、2.7、3.6、3.8の3バージョンがあることがわかる。 $ dnf module list 'python*' CentOS Linux 8 - AppStream Name Stream Profiles Summary python27 2.7 [d] common [d] Python programming language, version 2.7 python36 3.6 [d][e] build, common [d] Python programming language, version 3.6 python38 3.8 [d] build, common [d] Python programming language, version 3.8 Hint: [d]efault, [e]nabled, [x]disabled, [i]nstalled 次に現在インストールされているPythonを調べてみよう。一番簡単な方法は次のコマンドだろう。このように表示されたときはPython 3.6がインストールされている。 $ ls /usr/bin/python* /usr/bin/python /usr/bin/python3 /usr/bin/python3.6 /usr/bin/python3.6m 3-2. RHEL8のPythonまとめ これまでわかったことは以下のとおり。次にインストール方法や切り替え方法を説明する。 Platform-Pythonは必ずインストールされているが、利用者が使うことは推奨されない ユーザーが利用できるPythonはインストールされていないことがある インストールされていないときは、利用者が明示的にインストールする必要がある リポジトリからインストール可能なPythonのバージョンは2.7、3.6、3.8である 4. Pythonのインストールとalternativesの活用 Python 3がインストールされていないときは、明示的にインストールする必要がある。そこで、Python 3をインストールするとともに、シンボリックリンクを切り替えるalternativesについて説明する。 4.1. Python 3をインストールする Python 3をインストールする。python3でなくpython36を指定しても同じだ。 # dnf install python3 -y インストールが終わると、バージョン3.6.8がインストールされたことがわかる。 $ python3 -V Python 3.6.8 ただし、バージョンを指定しないと起動できない。このことは、お作法的に正しいことのだが、どうしても起動したいときもあるだろう。その方法を次で説明する。 $ python -bash: python: command not found 4-2. alternativesによるシンボリックリンクの切り替え Python 3をインストールしてもpythonコマンドは無効のままだ。これを変更するにはシンボリックリンクを切り替えるalternativesを使う必要がある。 4-2-1. alternativesの設定確認 現在のalternativesの設定を確認する。表示の見方は一番左が入力するコマンドで、一番右が実際に実行されるコマンドだ。 $ alternatives --list | grep python python auto /usr/libexec/no-python ★no-python python3 auto /usr/bin/python3.6 この結果を見るとpythonは/usr/libexec/no-pythonを参照している。名前からもわかるように何も実行されない。 pythonでpython3を起動する方法はman unversioned-pythonで紹介されている。 manの内容 UNVERSIONED-PYTHON(8) System Manager's Manual UNVERSIONED-PYTHON(8) NAME unversioned-python - info on how to set up the `python` command. SYNOPSIS unversioned-python DESCRIPTION unversioned-python The "unversioned" `python` command (/usr/bin/python) is missing by default. We recommend using `python3` or `python2` instead. If using the explicit versioned command is inconvenient, you can use `alternatives` to configure `python` to launch either Python 3 or Python 2. Note: The `python3` or `python2` package needs to be installed before its functionality is selected. EXAXPLES alternatives --config python Interactively select what the `python` command runs. alternatives --set python /usr/bin/python3 Configure the `python` command to run Python 3 Note: this is non-standard behavior according to [PEP 394]. 4-2-2. alternativesの設定変更 alternativesの設定を変更するには次の二つの方法がある。今回は対話的に設定する。 対話的に実行:alternatives --config python 指定して実行:alternatives --set python /usr/bin/python3 対話的に設定する # alternatives --config python There are 2 programs which provide 'python'. Selection Command ----------------------------------------------- *+ 1 /usr/libexec/no-python 2 /usr/bin/python3 Enter to keep the current selection[+], or type selection number: 2 ★2を入力 変更が終わるとpythonで3.6を実行できるようになる。 $ python -V Python 3.6.8 $ alternatives --list | grep python python manual /usr/bin/python3 python3 auto /usr/bin/python3.6 4-2-3. alternativesの設定詳細 alternativesについて、もう少し詳しく説明する。シンボリックリンクを切り替えるだけならばln -sコマンドでもよさそうだが、alternativesにはln -sにはない優れたメリットがある。そのことについて説明する。 alternatives --display <設定名>で設定の詳細を確認できる。わかりづらいかもしれないが、pythonコマンドから/usr/bin/python3が起動されることがわかる。 $ alternatives --display python python - status is manual. link currently points to /usr/bin/python3 ★これが現在の設定 /usr/libexec/no-python - priority 404 slave unversioned-python: (null) slave unversioned-python-man: /usr/share/man/man1/unversioned-python.1.gz /usr/bin/python3 - priority 300 slave unversioned-python: /usr/bin/python3 ★上記設定からリダイレクトされ、これが実行される slave unversioned-python-man: /usr/share/man/man1/python3.1.gz Current `best' version is /usr/libexec/no-python. 次にpython3の設定を確認してみよう。するとmanに加え、pip3など他のコマンドも表示される。 $ alternatives --display python3 python3 - status is auto. link currently points to /usr/bin/python3.6 /usr/bin/python3.6 - priority 1000000 slave easy_install-3: /usr/bin/easy_install-3.6 slave pip-3: /usr/bin/pip-3.6 slave pip3: /usr/bin/pip3.6 slave pydoc-3: /usr/bin/pydoc3.6 slave pydoc3: /usr/bin/pydoc3.6 slave pyvenv-3: /usr/bin/pyvenv-3.6 slave python3-man: /usr/share/man/man1/python3.6.1.gz Current `best' version is /usr/bin/python3.6. つまりalternativesによって、一括でシンボリックリンクを変更できるだけでなく、システムとして統一したインターフェースを提供することで操作ミスを防止できるのだ。 alternativesはJDKの切り替えにもよく使われ、Ubuntuでは同等のupdate-alternativesが利用できる。 5. Python 3.8をインストールする ここまでの説明が理解できれば2.7と3.8にも対応できると思うが、Python 3.8について説明する。 Python 3.8をインストールする。 # dnf install python38 2.python3.8コマンドでは3.8が起動するが、python3コマンドでは3.6が起動する。 $ python3.8 -V Python 3.8.3 $ python3 -V Python 3.6.8 ヒント:パッケージ名はpython38だがコマンドはpython3.8であることに注意。 3.設定を変更するには、同様にalternativesを使えばいい。 $ alternatives --display python3 python3 - status is auto. link currently points to /usr/bin/python3.6 ★この行が重要。3.6を指している。 /usr/bin/python3.6 - priority 1000000 slave easy_install-3: /usr/bin/easy_install-3.6 slave pip-3: /usr/bin/pip-3.6 slave pip3: /usr/bin/pip3.6 slave pydoc-3: /usr/bin/pydoc3.6 slave pydoc3: /usr/bin/pydoc3.6 slave pyvenv-3: /usr/bin/pyvenv-3.6 slave python3-man: /usr/share/man/man1/python3.6.1.gz /usr/bin/python3.8 - priority 3800 slave easy_install-3: /usr/bin/easy_install-3.8 slave pip-3: /usr/bin/pip-3.8 slave pip3: /usr/bin/pip3.8 slave pydoc-3: /usr/bin/pydoc3.8 slave pydoc3: /usr/bin/pydoc3.8 slave pyvenv-3: (null) slave python3-man: /usr/share/man/man1/python3.8.1.gz Current `best' version is /usr/bin/python3.6. 4.alternativesで切り替えるとpython3コマンドが3.8を参照するようになる。 # alternatives --set python3 /usr/bin/python3.8 $ python3 -V Python 3.8.3 6. Pythonのバージョンを明示的に指定するべし manに書かれている「PEP 394 -- The "python" Command on Unix-Like Systems」では、いくつかのリコメンデーションが紹介されている。 python2コマンドはPython 2を起動 python3コマンドはPython 3を起動 pythonコマンドはインストールされているPython 3を起動 ここで重要なのは、スクリプトのトラブルを防止するために、Shebang(シェバン)――スクリプト先頭の#!/path/to/file――では#!/usr/bin/python3のように明示的にバージョンを指定するべきだと。 また、これまでの経緯として/usr/bin/pythonのようにバージョンを指定しないのは行儀が悪いとも書かれている。 まとめると、以下のとおり。 「/usr/bin/python3」のように明示的にバージョンを指定する 小数点1桁までバージョンを指定するときは「/usr/bin/python3.8」のように指定する 「/usr/bin/python」で起動するPythonのバージョンは環境依存なので、なるべく使用しない 7. まとめ RHEL8系ディストリビューションには次の3種類のPythonがある システムが利用するPython 3.6(Platform-Python) Python 3。デフォルトは3.6。他に3.8も利用可能 Python 2。おもに移行用 Platform-Pythonは/usr/libexec/platform-pythonにインストールされ、ユーザーが利用することは推奨されない 環境によってはPython 3がインストールされていないことがある。そのときには自分でインストールする必要がある 複数バージョンのPythonを切り替えるにはalternativesを使用する Shebangにおける指定方法 「/usr/bin/python3」のように明示的にバージョンを指定する 小数点1桁までバージョンを指定するときは「/usr/bin/python3.8」のように指定する 「/usr/bin/python」で起動するPythonのバージョンは環境依存なので、なるべく使用しない
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Python】ブックの作成者の変更を行う。

pythonを使用してExcelファイルの操作を勉強しています。 本日の気づき(復習)は、ブックの作成者(最終更新者)の変更に関してです。 pythonでExcelを操作するため、openpyxlというパッケージを使用しています。 上記の様な作成者(最終更新者)名を この様に変更したいです。 creator属性と、lastModifiedBy属性 Workbook.properties.creator = '作者名' Workbook.properties.lastModifiedBy = '最終更新者名' 公式には記載を見つけられませんでしたが、 上記のようにWorkbook.propertiesのcreator属性で作者名を Workbook.propertiesのlastModifiedBy属性で最終更新者名を それぞれ変更できるようです。 他にも作成日付の変更や、最終印刷日の変更もできるようです。 詳しくは下の下のリンクをご確認ください。 最終的なコード from openpyxl import load_workbook wb = load_workbook('資料.xlsx') name = 'hogefuga' properties = wb.properties properties.creator = name properties.lastModifiedBy = name wb.save('資料_作成者変更.xlsx') 個人的には、あまり多用したくない内容だなとは思いました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GPT-3でanswerとcompletionのエンドポイントを比較する

概要 GPT-3には分類,回答,完了という3つのエンドポイントがあるが,answerとcompletionの違いがよくわからなかったので比較してみた. Answer まずファイルをあげる必要がある, 形式はjsonlという行ごとにJson形式になっているファイルを用意した. test.jsonl {"text": "puppy A is happy", "metadata": "emotional state of puppy A"} {"text": "puppy B is sad", "metadata": "emotional state of puppy B"} {"text": "Python(パイソン)はインタープリタ型の高水準汎用プログラミング言語である。", "metadata": "Pythonの説明"} {"text": "地球観測衛星は,地球の陸や海、大気などを宇宙から観測し、災害や地球温暖化の対策などに役立てる人工衛星。天気予報に生かす気象衛星や軍事目的の偵察衛星などもある。 多くの衛星は主に高度約400~1000キロメートルから、一定期間をかけて地球を観測している。", "metadata": "地球観測衛星の説明"} {"text": "コモンズの悲劇とは,共有の資源を巡って、個人の利益を追求しすぎるあまり、全体としては不利益を被ってしまうことへの警鐘。米生態学者のギャレット・ハーディン氏が1968年に唱えた。共有地(コモンズ)の悲劇ともいう。 ", "metadata": "コモンズの悲劇の説明"} {"text": "ライフサイクルアセスメントとは,製品やサービスが生まれてから廃棄されるまでのライフサイクル(一生)を通じた環境負荷を評価する取り組み。LCAともいう。ライフサイクルは自動車のような工業製品であれば原料となる鉄などの資源採掘から製造、使用、メンテナンス、リサイクル、廃棄までを指す。", "metadata": "ライフサイクルの説明"} これをアップロードする def main(): openai.api_key = OPENAI_API_KEY a = openai.File.create(file=open("{folder}/test.jsonl".format(folder=CURRENT_DIRECTORY)), purpose='answers') print(a) 試してみる. def main(): openai.api_key = OPENAI_API_KEY rtrn = openai.Answer.create( search_model="ada", model="davinci", question="Javaとはなんですか?", file="file-JQoVCw8rmPrD9r4HBU8lEKRc", examples_context="Pythonはプログラミング言語の一つです.", examples=[['Pythonはどんな言語ですか?', 'Python(パイソン)はインタープリタ型の高水準汎用プログラミング言語である。グイド・ヴァン・ロッサムにより創り出され、1991年に最初にリリースされたPythonの設計哲学は、有意なホワイトスペース(オフサイドルール)の顕著な使用によってコードの可読性を重視している。その言語構成とオブジェクト指向のアプローチは、プログラマが小規模なプロジェクトから大規模なプロジェクトまで、明確で論理的なコードを書くのを支援することを目的としている。Pythonは動的に型付けされていて、ガベージコレクションされている。構造化(特に手続き型)、オブジェクト指向、関数型プログラミングを含む複数のプログラミングパラダイムをサポートしている。Pythonは、その包括的な標準ライブラリのため、しばしば「バッテリーを含む」言語と表現される[4]。Pythonは1980年代後半にABC言語の後継として考案された。2000年にリリースされたPython 2.0では、リスト内包表記や参照カウントによるガベージコレクションシステムなどの機能が導入された。2008年にリリースされたPython 3.0は、完全な下位互換性を持たない言語の大規模な改訂であり、Python 2のコードの多くはPython 3では変更なしには動作しない。Python 2言語は2020年に正式に廃止され(当初は2015年予定)、"Python 2.7.18はPython 2.7の最後のリリースであり、したがってPython 2の最後のリリースである "[5]とされている。これ以上のセキュリティパッチやその他の改善はリリースされない[6]。Python 2が終了したことで、サポートされるのはPython 3.5.x以降[7]のみとなる。Pythonのインタプリタは多くのOSに対応している。プログラマーのグローバルコミュニティは、無料のオープンソース [8] リファレンス実装であるCPythonを開発および保守している 。非営利団体であるPythonソフトウェア財団は、PythonとCPythonの開発のためのリソースを管理・指導している。']], max_rerank=10, max_tokens=500, temperature=0.6, stop=["\n", "<|endoftext|>"] ) print(rtrn["answers"][0]) davinciの場合 Javaは、Sun Microsystems社が開発したオブジェクト指向プログラミング言語です。 Javaは、C言語やC++のような関数型言語ではなく、オブジェクト指向言語です curieの場合 Javaは、不可逆のクラスタリングシステムである,ジャーナル・コード・ライブラリ(JAR)によって記述された静的なプログラムである。 Javaは、言語の評価やプログラミングのコーディングのための多くの基本的な機能を提供するために開発された。 JVM(Java Virtual Machine)は、Javaのプログラミング言語であるJavaScriptに対応するプログラム・インタープリタを実行するためのプログラムである。 ライフサイクルアセスメントとは,製品やサービスが生まれてから廃棄されるまでのライフサイクル(一生)を通じた環境負荷を評価する取り組み。LCAともいう。 ライフサイクルは自動車のような工業製品であれば原料となる鉄などの資源採掘から製造、使用、メンテナンス、リサイクル、廃棄までを指す。 ポイント 返答が長い examplesで与えた文字列が長いため.max_tokensを500のままにしてもexamplesで与えた文字列が短いと返答も短くなる 与えたドキュメントの情報を無理矢理入れようとしている curieの場合,JavaやPythonとは関係のない情報を参照サンプルにしたら,入れ込もうとしてきた. Completionとは異なり,結構生真面目に元のデータを参照しようとしている. Complettion def main(): translate_text = 'Javaはどんな言語ですか?' openai.api_key = OPENAI_API_KEY prompt = 'プログラミング言語について詳しく知りたいです。\n' dics = { 'Pythonはどんな言語ですか?':'Python(パイソン)はインタープリタ型の高水準汎用プログラミング言語である。グイド・ヴァン・ロッサムにより創り出され、1991年に最初にリリースされたPythonの設計哲学は、有意なホワイトスペース(オフサイドルール)の顕著な使用によってコードの可読性を重視している。その言語構成とオブジェクト指向のアプローチは、プログラマが小規模なプロジェクトから大規模なプロジェクトまで、明確で論理的なコードを書くのを支援することを目的としている。Pythonは動的に型付けされていて、ガベージコレクションされている。構造化(特に手続き型)、オブジェクト指向、関数型プログラミングを含む複数のプログラミングパラダイムをサポートしている。Pythonは、その包括的な標準ライブラリのため、しばしば「バッテリーを含む」言語と表現される[4]。Pythonは1980年代後半にABC言語の後継として考案された。2000年にリリースされたPython 2.0では、リスト内包表記や参照カウントによるガベージコレクションシステムなどの機能が導入された。2008年にリリースされたPython 3.0は、完全な下位互換性を持たない言語の大規模な改訂であり、Python 2のコードの多くはPython 3では変更なしには動作しない。Python 2言語は2020年に正式に廃止され(当初は2015年予定)、"Python 2.7.18はPython 2.7の最後のリリースであり、したがってPython 2の最後のリリースである "[5]とされている。これ以上のセキュリティパッチやその他の改善はリリースされない[6]。Python 2が終了したことで、サポートされるのはPython 3.5.x以降[7]のみとなる。Pythonのインタプリタは多くのOSに対応している。プログラマーのグローバルコミュニティは、無料のオープンソース [8] リファレンス実装であるCPythonを開発および保守している 。非営利団体であるPythonソフトウェア財団は、PythonとCPythonの開発のためのリソースを管理・指導している。', 'Scalaはどんな言語ですか?':'Scala(スカラ、SKAH-lah[3])はオブジェクト指向言語と関数型言語の特徴を統合したマルチパラダイムのプログラミング言語である。名前の「Scala」は英語の「scalable language」に由来するものである。', 'Rubyはどんな言語ですか?':'Ruby(ルビー)は、まつもとゆきひろ(通称: Matz)により開発されたオブジェクト指向スクリプト言語(スクリプト言語とはプログラミング言語の一分類)。日本で開発されたプログラミング言語としては初めて国際電気標準会議(IEC)で国際規格に認証された事例となった[3]。' } for q,a in dics.items(): prompt += "Q: {question}\nA: {answer}\n###\n".format(question=q, answer=a) prompt += "Q: {text}\nA:".format(text=translate_text) print('here4',prompt) response = openai.Completion.create( engine='davinci', prompt=prompt, temperature=float(0.3), max_tokens=int(300), top_p=1.0, frequency_penalty=0.0, presence_penalty=0.0, stop=["###"] ) #export_text = _translate_text(target='ja', text=response["choices"][0]['text']) export_text = response["choices"][0]['text'] print(export_text) Java(ジャバ)は、Sun Microsystemsにより開発されたオブジェクト指向プログラミング言語である。 Javaは、Java Platform, Standard Edition (Java SE)、Java Platform, Enterprise Edition (Java EE)、Java Platform, Micro Edition (Java ME)の3つのプラットフォームに分類される。 Javaは、Java Platform, Standard Edition (Java SE)の一部である。 Java Platform, Standard Edition (Java SE)は、Java Platform, Micro Edition (Java ME)とJava Platform, Enterprise Edition (Java EE)の両方ともに、Java Platform, Standard Edition (Java SE)に含まれる。 Java Platform, Standard Edition (Java SE)には、Java Platform, Micro Edition (Java ME)とJava Platform, Enterprise Edition (Java EE)には含まれない、Java Platform, Standard Edition (Java SE)に特有のAPIが含まれている。 Java Platform, Standard Edition (Java SE)は、Java Platform, Micro Edition (Java ME)とJava Platform, Enterprise Edition (Java EE)の両方ともに、Java Platform, Standard Edition (Java SE)に含まれる 全体的にJavaのなかでちゃんと情報を収めようとしている. パラメータを調整してみる. def main(): translate_text = 'Javaはどんな言語ですか?' openai.api_key = OPENAI_API_KEY prompt = '' dics = { 'Pythonはどんな言語ですか?':'Python(パイソン)はインタープリタ型の高水準汎用プログラミング言語である。グイド・ヴァン・ロッサムにより創り出され、1991年に最初にリリースされたPythonの設計哲学は、有意なホワイトスペース(オフサイドルール)の顕著な使用によってコードの可読性を重視している。', 'Scalaはどんな言語ですか?':'Scala(スカラ、SKAH-lah[3])はオブジェクト指向言語と関数型言語の特徴を統合したマルチパラダイムのプログラミング言語である。名前の「Scala」は英語の「scalable language」に由来するものである。', 'Rubyはどんな言語ですか?':'Ruby(ルビー)は、まつもとゆきひろ(通称: Matz)により開発されたオブジェクト指向スクリプト言語(スクリプト言語とはプログラミング言語の一分類)。日本で開発されたプログラミング言語としては初めて国際電気標準会議(IEC)で国際規格に認証された事例となった[3]。' } for q,a in dics.items(): prompt += "Q: {question}\nA: {answer}\n###\n".format(question=q, answer=a) prompt += "Q: {text}\nA:".format(text=translate_text) print('here4',prompt) response = openai.Completion.create( engine='davinci', prompt=prompt, temperature=float(0.3), max_tokens=int(300), top_p=1.0, frequency_penalty=0.0, presence_penalty=0.0, stop=["###"] ) #export_text = _translate_text(target='ja', text=response["choices"][0]['text']) export_text = response["choices"][0]['text'] print(export_text) davinciの場合 Java(ジャバ)は、Sun Microsystemsが開発したオブジェクト指向プログラミング言語である。 Javaは、オブジェクト指向言語と関数型言語の特徴を統合したマルチパラダイムのプログラミング言語である。 Javaは、C++やJavaScriptなどの言語と同様に、Java Virtual Machine(JVM)によって実行される。 curieの場合 A: Java(ジャイアント)は、Sun Microsystems(通称: Sun)により開発されたオブジェクト指向プログラミング言語である。 Javaは、プログラミング言語の一分類として、その名前にちなんで「ジャイアント」と呼ばれる 雰囲気はだいぶ良くなった.実際とは異なる内容を喋っているのが気になるが. 所感 completionは事実と異なることをいうのでクリエイティブなことには使えるものの事実に関する記事などは書けない.フェイク記事になる. Answerは堅いがトークン数が多くなりがち. クリエイティブ要素ならCompletionを使い,基本はAnswerにしておくと良さそう. コード めっちゃ汚いけどコードもあげておく # coding: utf-8 import os import io import sys import six import yaml import time import string import random from datetime import datetime, date from google.cloud import translate_v2 as translate import openai with open('./secret.yaml', 'r') as yml: config = yaml.load(yml) OPENAI_API_KEY = config['env_variables']['OPENAI_API_KEY'] CURRENT_DIRECTORY = os.getcwd() def main(): translate_text = 'Javaはどんな言語ですか?' openai.api_key = OPENAI_API_KEY prompt = '' dics = { 'Pythonはどんな言語ですか?':'Python(パイソン)はインタープリタ型の高水準汎用プログラミング言語である。グイド・ヴァン・ロッサムにより創り出され、1991年に最初にリリースされたPythonの設計哲学は、有意なホワイトスペース(オフサイドルール)の顕著な使用によってコードの可読性を重視している。', 'Scalaはどんな言語ですか?':'Scala(スカラ、SKAH-lah[3])はオブジェクト指向言語と関数型言語の特徴を統合したマルチパラダイムのプログラミング言語である。名前の「Scala」は英語の「scalable language」に由来するものである。', 'Rubyはどんな言語ですか?':'Ruby(ルビー)は、まつもとゆきひろ(通称: Matz)により開発されたオブジェクト指向スクリプト言語(スクリプト言語とはプログラミング言語の一分類)。日本で開発されたプログラミング言語としては初めて国際電気標準会議(IEC)で国際規格に認証された事例となった[3]。' } for q,a in dics.items(): prompt += "Q: {question}\nA: {answer}\n###\n".format(question=q, answer=a) prompt += "Q: {text}\nA:".format(text=translate_text) response = openai.Completion.create( engine='curie', prompt=prompt, temperature=float(0.3), max_tokens=int(300), top_p=1.0, frequency_penalty=0.0, presence_penalty=0.0, stop=["###"] ) export_text = response["choices"][0]['text'] print(export_text) if __name__ == "__main__": main()
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LeetCodeWeekly238C: 1839. Longest Substring Of All Vowels in Order 区間操作 一定の文字出現する最大の単調増加文字列

題意(オリジナル) 英語小文字の集合である文字列$s$が与えられる. 良い文字列を以下のように定義する.ソートされた$x$文字の連続した文字列であり、この中に$a,i,u,e,o$の5文字が1回以上出現していなければならない. この文字列の長さの最大長を求めよ こう考えた 簡単のため、問題文を以下のように言い換える. $|s|$の配列$a$が与えられ、各要素 $a_i$は $0 \leq a_i \leq 25$である よい区間とは以下の通りである.連続した区間の要素が全てソートされており(つまり、単調増加)、この中に$0, 8, 20, 4, 15$が1度以上含まれている ここで、連続した区間とは、ある任意の $ 0 \leq l \leq r < |s| $と言い換えられる.さて、ここで単調増加である条件を考えると、ある$l$を固定した際、$r$を右に伸ばしていき、伸ばせるところまで伸ばし、その中に、$0, 8, 20, 4, 15$が含まれているならばそれは最長の長さの候補として扱える. このため、以下のように判定をする. l = 0からスタートし、単調増加で有る限り、rをインクリメントする 単調増加でなくなった場合、今の区間に必要な文字が含まれているかを判定する. Yesの場合、その文字長を候補とする.Noの場合、捨てる 実装 特に留意点はなし.工夫は以下程度. - 先に$s$は数値のリストにしておく方が良い class Solution: def longestBeautifulSubstring(self, word: str) -> int: judge = lambda : cnt[0]!=0 and cnt[8]!=0 and cnt[20]!=0 and cnt[4]!=0 and cnt[14]!=0 chr2int = lambda x: ord(x) - ord("a") s,l,r = word,0,0 s = list(map(chr2int, s)) cnt = [0] * 26 res = 0 p = -1 while r < len(s): cnt[s[r]] += 1 # 足した文字が条件を達成しているか? if s[r] < p: l = r r += 1 p = s[r] continue p = s[r] if judge(): # 文字が足りている res = max(res, (r-l) + 1) r += 1 return res
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

生産現場IoTへの挑戦 #05 ~データベースのインストールと設定~

1.はじめに I2C接続のセンサーを使用してデータが取れる様になり、全体システムのおぼろげながら構想もできましたので、データの蓄積方法を決めます。 ネットの記事などを見渡すと、IoTのデータはクラウドを活用して収集や集計を行うのが流行りだし格好いいと思うのですが、「クラウドって何となく怖い」とか「クラウド使うお金がない」とか「社外にデータを持ち出すなんてまかりならん」とか「そもそも外部サーバを使っていいものかどうか判断できる人がいない」とかいろいろな理由で社内でコンパクトにシステムを組みたいという場合は、センサー制御用のラズパイにデータベースを構築してしまうという手があります。 (状況が許すならこんなのやこんなのを使って、流行りのかっこいいクラウドIoTをやってみたいものです) プロの方が見たら信頼性の低いラズパイにデータを蓄積するなんて!!! とお怒りの言葉をいただきそうな気もしますが、まずは手軽にIoTを体験するための方便だということでお許し願いたいと思います。 同様のシステムにトライしようという奇特な方がいらっしゃっても、あくまでもIoTの味見をするための簡易システムであり、不測の事故によりデータが無くなる危険があることをご理解ください。 また、データベースの初期設定等について説明しますが、データベースについては今回の案件で触り始めた超初心者でのすの間違いや不適切な使用方法もあるかもしれません。 データベースの使用方法については他の解説サイトや書籍にてより詳しく勉強し、当記事の間違いなどをやさしく指摘していただけると幸いです。 2.MariaDBをインストールする。 前回も軽く触れましたが、使用するデータベースソフトはMariaDBというMySQL互換のフリーソフトです。 これをインストールして、必要なデータベースの設定を行います。 2-1.インストール方法 MariaDBのインストールはターミナル上から行います。 次のコマンドでインストールしてください。 $ sudo apt-get install mariadb-server 2-2.リモートでのログインを許可する MariaDBの設定は次項で説明する通り、リモート環境で実施しますのでネットワーク越しにアクセスできる様に設定しなければなりません。 設定についてはこちらのページで丁寧に説明されていますのでこの通りに実施して下さい。 メモとして必要なコマンドのみ記載します。 $ sudo mysql -u root MariaDB [(none)]> USE mysql; MariaDB [mysql]> UPDATE user SET plugin='' WHERE User='root'; MariaDB [mysql]> exit $ sudo systemctl restart mysql $ mysql -u root MariaDB [(none)]> update mysql.user set password=password('パスワード') where user = 'root'; MariaDB [mysql]> exit $ sudo systemctl restart mysql ※パスワードは、任意のパスワードに書き換えてください。 3.データベースの開発環境について ラズパイ上で使用するデータベースにはMariaDBを使用しますが、データベースを構築する際にラズパイ上で行うと結構厄介です。そこでデータベースの構築中はラズパイをLANに接続してWindows10マシンからリモートで構築します。 3-1.HeidiSQLについて HeidiSQLはWin10上で動くデータベース管理用のGUIソフトです。 MariaDBは、リモートログインを許可した際に用いたSQLと呼ばれる言語で制御できますが、毎回SQLを使うのはなかなかの苦行です。 HeidiSQLを使うと、GUIでデータベースの構築や設定、蓄積したデータの閲覧、出力ができるため非常に便利です。というか、私はGUIツールが無いとデータベースを扱える気がしません。 ラズパイ上で使用できるGUIツールもなくは無いのですが、いくつか試した中ではHeidiSQLが最も使いやすかったので今後の説明はHeidiSQLをメインに使用して説明します。 HeidiSQLの弱点は、ラズパイ上で動かせないことですが、同じLANに接続していればリモートアクセスも容易です。 ※Win10アプリをlinux上で動かすツールを使えばHeidiSQLも使えそうではありますが、まだ試していません。うまく動いたら報告します。 3-2.HeidiSQLをインストールする HeidiSQLはこちらの公式サイトからダウンロードできます。 インストールも特に問題ないと思いますが、こちらのサイトで丁寧に説明されているため判らない場合は参考にしてください。 4.データベースを作成する HeidiSQLがインストールできたら、ラズパイに接続してデータベースを作成します。 4-1.ラズパイのIPアドレスを確認する ラズパイの画面上部にあるネットワーク接続のアイコンをマウスオーバーするとIPアドレスが表示されます。 もしくはラズパイのターミナルを立ち上げてifconfigコマンドで接続状況を確認します。 inetに続く表示がIPアドレスです。 4-2.MariaDBに接続する HeidiSQLを立ち上げるとセッションマネージャーが開きますので接続設定を入力します。 4-2.データベースを作る MariaDBに接続したデータベースが表示されるため、右クリックして「新規作成」⇒「データベース」を選択します。 ウィンドウが開いたら、名前を入力して「OK」をクリックすると新しいデータベースが作成できます。 4-1.テーブルとカラムを作る データベースの中に、データを格納するテーブルを作成します。 先ほど選択したデータベースを右クリックし、「新規作成」⇒「テーブル」を選択します。 画面右にテーブルが表示されるため、テーブルの名前を入力し、カラムを追加します。 今回はBMP280の温度、気圧、湿度を記録するため、IDと時間を加えて5つのカラムを作成します。   4-2.カラムの設定を変更する カラムには様々なデータが記録できますが、記録するデータに合わせて入力規則を定義します。 今回は「名前」「データ型」「NULLを許可」「デフォルト」を下の通り設定します。変更したいセルをクリックすると変更できます。 ※今回はトラブル防止のため、測定時間を記録するカラムにDATETIME型、測定データを記録するカラムにDOUBLE型を使用していますがデータサイズを削減したい場合はTIMESTAMP型とFLOAT型でも対応可能です。 また、timeのカラムだけでもユニークになる予定ですが、役に立つかもしれないのでIDを用いてキーにします。 4-3.キーを設定する データベースを管理するために、キーとなるカラムを設定します。 「INDEX」タブを選択して、「追加」するとキーができますので、「タイプ/長さ」の「KEY」をダブルクリックして「PRIMARY」に変更します。 キーの表示が「PRIMARY」に変わるため、IDカラムを「PRIMARY」にドラッグするとIDが追加されます。 最後に「保存」をクリックするとテーブルができました。 5.まとめ 駆け足でしたが、ラズパイにデータベースを作成しました。 測定項目が増えても同様の手順でカラムやテーブルを増やしていけば記録できます。 最初は戸惑うことも多いかと思いますが、どんどん触って慣れましょう。 6.おまけ・・・ラズパイデータベースの破損について 冒頭にも書いた通り、ラズパイにデータベースを構成することにはデータ破損の危険性が伴います。ラズパイを用いたIoTシステムには常に付きまとう問題ですが、メインストレージにmicroSDのデータ破損に伴う事故が多いようです。 個人的な見解としては、このタイプの事故の最大の原因はmicroSDへの書き込み途中の電源遮断です。配線抜け、電源ブチ切り、工場の停電・瞬停などにより書き込み中に電源が落ちてmicroSDのデータが破損するようなケースです。 この対策としては次のいずれかの方法が有効です。  ①microSDカードをROMモードで使用する。  ②UPSを使用して、電源遮断時に安全にシャットダウンする。 今回は、データベースとして使用するため、microSDをROMモードで使用することはできず、②の対策が必要です。また別の機会にご紹介したいと思いますが、ラズパイ向けのUPS装置が市販されていますので、データ破損対策として導入されることをお勧めします。 ※ちなみに当記事を執筆している現在、ノーガードで運用中ですがなんとか耐えています。。。  UPS自作基板をいただいたのですがまだ手をつけられていません。。。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

APIで取得した株価データをcsvファイルに保存する方法

今回は、1分足や5分足のような小刻みの株価データを取得したいなと考えておりまして、こちらのタイトルに挑戦することになりました。 実行環境 MacOS VSCode Python3.7.7(anaconda) 【Python入門】プログラミングで自分だけの株価データを手に入れよう Python3 Yahoo Finance APIを試す pythonでYahoo Financeから株価の一分足データを取得する(投資活動日記 2020/06/18) 事前準備 まず、事前準備として、APIを使うためのライブラリをインストールする必要があります。 特に難しいことはなく、 pip install yahoo-finance-api2 こちらのコードをターミナルで打ち込むだけで、使えるようになります。 実際のコード from datetime import datetime import pandas as pd import sys import numpy as np from yahoo_finance_api2 import share from yahoo_finance_api2.exceptions import YahooFinanceError my_share = share.Share('MSFT') symbol_data = None try: symbol_data = my_share.get_historical(share.PERIOD_TYPE_DAY, 60, share.FREQUENCY_TYPE_MINUTE, 5) except YahooFinanceError as e: print(e.message) sys.exit(1) data = symbol_data['timestamp'] price = symbol_data['close'] new_data = [datetime.utcfromtimestamp(int(data[i]/1000)) for i in range(len(data))] all_data = np.array([new_data, price]).T all_data = pd.DataFrame(all_data) all_data.to_csv('deep_5m.csv', mode='w', header=True) data = pd.read_csv('deep_5m.csv') print(data['0']) そこまで長くないコードかと思われます。 yahoo-finance-api2 0.0.11 こちらのリンクから、公式サイトにアクセスできまして、公式サイトが大体の雛形を作っていますので、使うと良いかと思われます。 コードの解説 順にコードを解説していきたいと思います。 大体の雛形 from yahoo_finance_api2 import share from yahoo_finance_api2.exceptions import YahooFinanceError my_share = share.Share('MSFT') symbol_data = None try: symbol_data = my_share.get_historical(share.PERIOD_TYPE_DAY, 60, share.FREQUENCY_TYPE_MINUTE, 5) except YahooFinanceError as e: print(e.message) sys.exit(1) まず、こちらのコードですが、こちらはほとんど公式サイトをパクったやつなので、そこまで人によって違うということはないかと思われます。 share.FREQUENCY_TYPE_MINUTEの後ろが5になっておりますが、これは5分毎の株価データを取得していることになります。 こちらの数字を変更して、自分用にアレンジすると良いかと思います。 また、share.PERIOD_TYPE_DAYの後ろが60になっておりますが、こちらは60日分のデータを取得していることになります。こちらも数字を変えたり、DAYの部分をYEARなどに変えて自分用にすると良いかと思います。 取得したデータをカスタマイズ data = symbol_data['timestamp'] price = symbol_data['close'] new_data = [datetime.utcfromtimestamp(int(data[i]/1000)) for i in range(len(data))] all_data = np.array([new_data, price]).T all_data = pd.DataFrame(all_data) 取得したデータは、辞書型で格納されており、キーは全部で、timestamp, open, high, low, close, adj_close, volumeを含まれておりまして、値はリスト型で格納されております。 なので、まずは'timestamp'と'close'をキーにして、日時と終値を取得します。 timestampの表示を変更 timestampは何も変更しないと、1614589500000みたいな数字の羅列で格納されています。 自分も詳しいことはわからないのですが、 PythonでUNIX時間(エポック秒)と日時datetimeを相互変換 こちらの記事にある、UNIX時間を表しているのかなと思いました。 そこで、 datetime.utcfromtimestamp(int(data[i]/1000)) こちらのコードを書くことで、通常の日時に変更することができます。 1000で割っているのは、ミリ秒表示されてしまっており、単位を合わせるために割っているとのことです。 そのあとは、timestampとpriceを転置させて行列の形にしました。 データをcsvファイルに保存する all_data.to_csv('deep_5m.csv', mode='w', header=True) data = pd.read_csv('deep_5m.csv') print(data['0']) こちらは、そこまで難しくないかと思います。 まとめ APIはなんか面倒くさそうだなと思って、毛嫌いしていたのですが、やってみたら意外と簡単にできました。 アクセスする頻度を調整する必要があるみたいですが、しっかり使えれば便利だなと思いました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python:日付情報の扱い方について

はじめに Pythonで日付のデータを扱う方法についてまとめました。Pythonで日付を扱うための標準ライブラリの中に以下のクラスを持っています。 datetimeモジュール -> dateクラス/timeクラス/datetimeクラス timeモジュール -> timeクラス datetimeモジュール dateクラス sample01 >>> from datetime import date >>> a = date(2021,12,24) >>> a.year 2021 >>> a.month 12 >>> a.day 24 >>> a.isoformat() '2021-12-24' 定義した日付を文字列で出力したい場合は、isoformat()関数で実行できます。 1日後、2日後、1週間後、1週間前などの日を計算で出したい場合は、timedelta()クラスを利用します。 sample02 >>> from datetime import date, timedelta >>> a = date.today() >>> a.isoformat() '2021-04-27' >>> one_day=timedelta(days=1) >>> b = a + one_day >>> b.isoformat() '2021-04-28' >>> c = a + 10 * one_day >>> c.isoformat() '2021-05-07' >>> d = a - one_day '2021-04-26' timeクラス sample03 >>> from datetime import time >>> a = time(12,2,3,4) >>> a.isoformat() '12:02:03.000004' >>> a.hour 12 >>> a.minute 2 >>> a.secound 3 >>> a.microsecond 4 datetimeクラス sample04 >>> from datetime import datetime >>> a = datetime(2021,1,2,12,10,10,6) >>> a.isoformat() '2021-01-02T12:10:10.000006' combine()メソッドを使うと、date型とtime型のデータを結合してdatetime型のオブジェクトを生成します。 sample05 >>> from datetime import datetime, date, time >>> a = date(2021,1,2) >>> b = time(12,12,12) >>> c = datetime.combine(a, b) >>> c.isoformat() '2021-01-02T12:12:12.000000' timeモジュール timeモジュールのtime()関数によってUnix時間で表した現在時刻を返す。 sample06 >>> import time >>> now = time.time() >>> now 161951035 9.4188821 >>> time.ctime(now) 'Tue Apr 27 16:59:19 2021' 日時の表示フォーマット isoformat()メソッドやctime()メソッドの意外でも日時の指定したフォーマットで表示するためのメソッドとしてstrftime()があります。 sample07 >>> from datetime import datetime >>> now = datetime.today() >>> now.strftime('%Y-%m-%d(%b)') '2021-04-27(Apr)' >>> 書式には以下の指定子が利用できます。 書式指定子 日時の単位 範囲 %Y 年 1900- %m 月 01-12 %B 月名 January,,,December %b 月名略称 Jan,,,,Dec %d 日 01-31 %A 曜日 Sunday,,,,Saturday %a 曜日略称 Sun,,,,Sat %H 時間(24時間) 00-23 %I 時間(12時間) 01-12 %p AM/PM AM,PM %M 分 00-59 %S 秒 00-59
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

生産現場IoTへの挑戦 #04 システムの構成と簡単なテスト

1.はじめに 前回までの開発で、M5StickCを振動ピックアップとして利用できそうなことがわかりましたので、他にも測定したいデータ項目を整理して、全体のシステム構成を考えてみました。 あわせて、センサー類との通信に使用するI2C接続のテストと、測定時間を正確に記録するためのリアルタイムクロックの設定を行います。 2.システム構成のイメージ 前回までは振動センサーについて述べていましたが、実際に運用するシステムはもう少し欲張りな仕様となっています。 2-1.そもそも何がしたいのか? 今回の目的はプラスチック成型機の設備稼働状況の監視で、測定したいデータが複数あります。 設備稼働状況というと、生産管理に結びつくような生産状況情報(何を何個作ったとか、生産条件のトレンドデータなど)のイメージもありますが、今回は設備の故障や不具合を感知することが目的ですので、ユーティリティー関連の状態監視が目的です。 測定項目(予定) 測定対象 測定項目 センサー  センサー出力 環境 雰囲気温度 BMP280 I2C 環境 湿度 BMP280 I2C 環境 気圧 BMP280 I2C 油圧ポンプ 振動 M5StackC BTシリアル通信 油圧ポンプ 回転数 M5StackC BTシリアル通信 油圧ポンプ 瞬時電力 電流センサ アナログ電流 油圧ポンプ 瞬時電力 電流センサ アナログ電流 油圧ポンプ 瞬時電力 電圧センサ アナログ電圧 油圧ポンプ 圧力 圧力センサ アナログ電流 冷却水系統1 水温 熱電対 アナログ電圧 冷却水系統1 流量 流量計 アナログ電圧 冷却水系統2 水温 熱電対 アナログ電圧 冷却水系統2 流量 流量計 アナログ電圧 高圧エア 圧力 圧力センサ アナログ電圧 油圧ポンプ 圧力 圧力センサ アナログ電流 とりあえずいろいろ上げましたが、まずは環境の3パラメータとテスト済みの振動系のデータ採取から開始します。 他の項目はセンサー類の準備ができ次第順次追加することにしました。 2-2.システムの構成 今回はクラウドを使用しないことを宣言しましたが、そもそも測定現場にネットワーク環境が無いことも考えられる、というか今回のプロジェクト先ではネットワーク環境が無いため、スタンドアロンでも稼働することを前提にしています。 全体の構成は上図の通りです。 各種センサーとラズパイはBluetooth及びI2Cで接続します。環境センサーはBMP280というセンサーをI2C接続で使用します。また、今回はアナログ出力センサーを多く使用するためADS1115Sというアナログデジタル変換ボードを使用してラズパイとI2C接続します。ADS1115Sは4chのアナログ入力を持っていますので、必要に応じて追加します。ADS1115Sは一つのI2Cバスに最大4個まで接続できます。4×4=16個以上のアナログデータを入力したい場合もI2Cバスを変えるかI/Oエキスパンダー使用すれば接続数を増やすことが(たぶん)できますのでどんどんデータ測定しましょう。 DS3231はリアルタイムクロック(RTC)機能を追加するためのボードです。RTC機能を持ったPCは電源がオフになっても内蔵電池などで時計機能を維持しますが、ラズパイにはRTC機能がありませんので、ネットワーク接続の無い状態で電源を切ると時計が狂います。今回は時系列データを取ることが目的ですのでRTC機能を追加しています。 2-3.接続に関する注意点 このシステムは、I2CとBluetoothシリアルによる接続を前提としていますが、どちらもノイズや障害物、距離などの環境により接続が不安定になります。 I2C接続の場合、特別な対策をしない限り数十センチが目安です。Bluetoothは見通し無かったり、周囲に電磁波のノイズが多いと接続が不安定になります。 アナログ信号も電流出力の場合は比較的遠距離まで対応できますが、電圧出力の場合は信号線の抵抗によりデータが狂いますので注意が必要です。 3.データベース 測定したデータは、データベースに記録します。 CSVなどのファイルに保存することもできますが、膨大なデータをCSVファイルで管理するのは至難の業ですので、データベースによるデータ管理に挑戦しました。 使用したデータベースソフトは、ラズパイでよく使われるMariaDBです。MariaDBはフリーのデータベースとしてもっとも有名なMySQLの派生版で使い勝手もほぼ一緒です。(MySQLとMariaDBの比較) 使用方法の学習もMySQLの資料がそのまま使え、参考情報も広く頒布されているため採用しました。 4.I2C接続のテストとRTCの有効化 I2c接続のテストを兼ねて、DS3231によるRTCの有効化とBMP280による環境データの測定を行います。 4-1.接続方法 I2C接続では、VCC(電源)、GNDと信号用のSDC、SCLという4本の線を用いて接続します。 接続元のラズパイをマスター、接続先のセンサーをスレーブとして制御しますが4本の線を複数のスレーブ機器で共有できるため、数珠繋ぎ状の接続(デイジーチェーン)で簡単にスレーブ機器を増設できるという特徴があります。 DS3231とBMP280も上の模式図の通り、4本の配線を接続します。 ラズパイ DS3231 BMP280 3V3(Pin1) VCC VCC GND(Pin9) GND GND GPIO2(Pin3) SDA SDA GPIO3(Pin5) SCL SCL ラズパイでは使用できるI2C BUSは複数チャンネルありますが、今回はI2C1を使用しますのでSDAとSCLはそれぞれGPIO2と3(PIN3とPIN5)、VCCは3.3V(PIN1)を使用します。 4-2.DS3231の有効化 ※DS3231の有効化についてはこちらのサイトを参考にさせていただきました。 DS3231はLIR2032というボタン電池型のバッテリーを使用しますのでバッテリーを入れます。 充電機能を持ったボードですのでCR2032などの充電できないボタン電池は絶対に使用しないで下さい。 配線が接続できたら、LX terminalから以下の操作を行います。 ・I2Cの有効化 メニューから、「設定」⇒「Raspberry Piの設定」⇒「インターフェイス」タブ⇒「I2C」の「有効」をチェック ・DS3231の有効化 pi@raspberrypi:~ $ sudo apt-get purge fake-hwcloc pi@raspberrypi:~ $ sudo vi /boot/config.txt # viが立ち上がるので最後に次の行を追加して保存 dtoverlay=i2c-rtc,ds3231 pi@raspberrypi:~ $ sudo vi /etc/udev/rules.d/85-hwclock.rules # viが立ち上がり、新規ファイルを作成するので次の行を入力して保存 KERNEL=="rtc0", RUN+="/sbin/hwclock --rtc=$root/$name --hctosys" viというのはテキスト編集アプリですが、使い慣れていないと難しいかもしれません。 こちらのサイトなどで使用方法を確認してテキストを編集して保存しましょう。 ・I2C接続状況の確認 i2cdetectコマンドで、I2Cの接続状況が確認できます。 pi@raspberrypi:~ $ i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- 57、68が表示されている場合、配線は接続されていますがDS3231は有効化されていません。 有効化さると、68の部分がUUに変化します。 ラズパイをリブートしても有効化されない場合は次のコマンドを試してみてください。 pi@raspberrypi:~ $ sudo modprobe --first-time rtc-ds3232 4-3.BPM280による測定 BPM280による測定はpythonのプログラムで実行します。 ラズパイ標準のTohnnyもしくはvscodeなどでプログラミングしてください。 前回まではTohnnyを使用していましたが、最近vscodeを使い始めました。慣れるまでは若干の訓練が必要ですが、慣れると作業性が上がるためvscodeの使用をお勧めします。 まずは、ターミナルを開いて、次の二つのライブラリをインストールします。 pi@raspberrypi:~ $ sudo pip3 install smbus2 pi@raspberrypi:~ $ sudo pip3 install RPi.bme280 ライブラリが入ったら、サンプルコードで動作を確認します。 サンプルはこちらのコードを参考にしています。 import smbus2 import bme280 port = 1 #I2C1を使用するため1 address = 0x76 #BMP280のI2Cアドレス bus = smbus2.SMBus(port) #I2Cの設定 calibration_params = bme280.load_calibration_params(bus, address) #BMP280の設定値取得 data = bme280.sample(bus, address, calibration_params) #BMP280の測定値取得 print(data.timestamp) #測定時間表示 print("temperature : %s *C" % str(round(data.temperature,1))) #温度表示 print("pressure : %s %%" % str(round(data.pressure,1))) #気圧表示 print("humidity : %s hPa" % str(round(data.humidity,1))) #湿度表示 5.まとめ 今回は、ラズパイを使ったIoTシステム制作の前準備としてI2C接続とRTCの設定を行いました。 データ蓄積のためのデータベースの準備を行います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

生産現場IoTへの挑戦 #04 ~システムの構成と簡単なテスト~

1.はじめに 前回までの開発で、M5StickCを振動ピックアップとして利用できそうなことがわかりましたので、他にも測定したいデータ項目を整理して、全体のシステム構成を考えてみました。 あわせて、センサー類との通信に使用するI2C接続のテストと、測定時間を正確に記録するためのリアルタイムクロックの設定を行います。 2.システム構成のイメージ 前回までは振動センサーについて述べていましたが、実際に運用するシステムはもう少し欲張りな仕様となっています。 2-1.そもそも何がしたいのか? 今回の目的はプラスチック成型機の設備稼働状況の監視で、測定したいデータが複数あります。 設備稼働状況というと、生産管理に結びつくような生産状況情報(何を何個作ったとか、生産条件のトレンドデータなど)のイメージもありますが、今回は設備の故障や不具合を感知することが目的ですので、ユーティリティー関連の状態監視が目的です。 測定項目(予定) 測定対象 測定項目 センサー  センサー出力 環境 雰囲気温度 BMP280 I2C 環境 湿度 BMP280 I2C 環境 気圧 BMP280 I2C 油圧ポンプ 振動 M5StackC BTシリアル通信 油圧ポンプ 回転数 M5StackC BTシリアル通信 油圧ポンプ 瞬時電力 電流センサ アナログ電流 油圧ポンプ 瞬時電力 電流センサ アナログ電流 油圧ポンプ 瞬時電力 電圧センサ アナログ電圧 油圧ポンプ 圧力 圧力センサ アナログ電流 冷却水系統1 水温 熱電対 アナログ電圧 冷却水系統1 流量 流量計 アナログ電圧 冷却水系統2 水温 熱電対 アナログ電圧 冷却水系統2 流量 流量計 アナログ電圧 高圧エア 圧力 圧力センサ アナログ電圧 油圧ポンプ 圧力 圧力センサ アナログ電流 とりあえずいろいろ上げましたが、まずは環境の3パラメータとテスト済みの振動系のデータ採取から開始します。 他の項目はセンサー類の準備ができ次第順次追加することにしました。 2-2.システムの構成 今回はクラウドを使用しないことを宣言しましたが、そもそも測定現場にネットワーク環境が無いことも考えられる、というか今回のプロジェクト先ではネットワーク環境が無いため、スタンドアロンでも稼働することを前提にしています。 全体の構成は上図の通りです。 各種センサーとラズパイはBluetooth及びI2Cで接続します。環境センサーはBMP280というセンサーをI2C接続で使用します。また、今回はアナログ出力センサーを多く使用するためADS1115Sというアナログデジタル変換ボードを使用してラズパイとI2C接続します。ADS1115Sは4chのアナログ入力を持っていますので、必要に応じて追加します。ADS1115Sは一つのI2Cバスに最大4個まで接続できます。4×4=16個以上のアナログデータを入力したい場合もI2Cバスを変えるかI/Oエキスパンダー使用すれば接続数を増やすことが(たぶん)できますのでどんどんデータ測定しましょう。 DS3231はリアルタイムクロック(RTC)機能を追加するためのボードです。RTC機能を持ったPCは電源がオフになっても内蔵電池などで時計機能を維持しますが、ラズパイにはRTC機能がありませんので、ネットワーク接続の無い状態で電源を切ると時計が狂います。今回は時系列データを取ることが目的ですのでRTC機能を追加しています。 2-3.接続に関する注意点 このシステムは、I2CとBluetoothシリアルによる接続を前提としていますが、どちらもノイズや障害物、距離などの環境により接続が不安定になります。 I2C接続の場合、特別な対策をしない限り数十センチが目安です。Bluetoothは見通し無かったり、周囲に電磁波のノイズが多いと接続が不安定になります。 アナログ信号も電流出力の場合は比較的遠距離まで対応できますが、電圧出力の場合は信号線の抵抗によりデータが狂いますので注意が必要です。 3.データベース 測定したデータは、データベースに記録します。 CSVなどのファイルに保存することもできますが、膨大なデータをCSVファイルで管理するのは至難の業ですので、データベースによるデータ管理に挑戦しました。 使用したデータベースソフトは、ラズパイでよく使われるMariaDBです。MariaDBはフリーのデータベースとしてもっとも有名なMySQLの派生版で使い勝手もほぼ一緒です。(MySQLとMariaDBの比較) 使用方法の学習もMySQLの資料がそのまま使え、参考情報も広く頒布されているため採用しました。 4.I2C接続のテストとRTCの有効化 I2c接続のテストを兼ねて、DS3231によるRTCの有効化とBMP280による環境データの測定を行います。 4-1.接続方法 I2C接続では、VCC(電源)、GNDと信号用のSDC、SCLという4本の線を用いて接続します。 接続元のラズパイをマスター、接続先のセンサーをスレーブとして制御しますが4本の線を複数のスレーブ機器で共有できるため、数珠繋ぎ状の接続(デイジーチェーン)で簡単にスレーブ機器を増設できるという特徴があります。 DS3231とBMP280も上の模式図の通り、4本の配線を接続します。 ラズパイ DS3231 BMP280 3V3(Pin1) VCC VCC GND(Pin9) GND GND GPIO2(Pin3) SDA SDA GPIO3(Pin5) SCL SCL ラズパイでは使用できるI2C BUSは複数チャンネルありますが、今回はI2C1を使用しますのでSDAとSCLはそれぞれGPIO2と3(PIN3とPIN5)、VCCは3.3V(PIN1)を使用します。 4-2.DS3231の有効化 ※DS3231の有効化についてはこちらのサイトを参考にさせていただきました。 DS3231はLIR2032というボタン電池型のバッテリーを使用しますのでバッテリーを入れます。 充電機能を持ったボードですのでCR2032などの充電できないボタン電池は絶対に使用しないで下さい。 配線が接続できたら、LX terminalから以下の操作を行います。 ・I2Cの有効化 メニューから、「設定」⇒「Raspberry Piの設定」⇒「インターフェイス」タブ⇒「I2C」の「有効」をチェック ・DS3231の有効化 pi@raspberrypi:~ $ sudo apt-get purge fake-hwcloc pi@raspberrypi:~ $ sudo vi /boot/config.txt # viが立ち上がるので最後に次の行を追加して保存 dtoverlay=i2c-rtc,ds3231 pi@raspberrypi:~ $ sudo vi /etc/udev/rules.d/85-hwclock.rules # viが立ち上がり、新規ファイルを作成するので次の行を入力して保存 KERNEL=="rtc0", RUN+="/sbin/hwclock --rtc=$root/$name --hctosys" viというのはテキスト編集アプリですが、使い慣れていないと難しいかもしれません。 こちらのサイトなどで使用方法を確認してテキストを編集して保存しましょう。 ・I2C接続状況の確認 i2cdetectコマンドで、I2Cの接続状況が確認できます。 pi@raspberrypi:~ $ i2cdetect -y 1 0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- 57 -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- 57、68が表示されている場合、配線は接続されていますがDS3231は有効化されていません。 有効化さると、68の部分がUUに変化します。 ラズパイをリブートしても有効化されない場合は次のコマンドを試してみてください。 pi@raspberrypi:~ $ sudo modprobe --first-time rtc-ds3232 4-3.BPM280による測定 BPM280による測定はpythonのプログラムで実行します。 ラズパイ標準のTohnnyもしくはvscodeなどでプログラミングしてください。 前回まではTohnnyを使用していましたが、最近vscodeを使い始めました。慣れるまでは若干の訓練が必要ですが、慣れると作業性が上がるためvscodeの使用をお勧めします。 まずは、ターミナルを開いて、次の二つのライブラリをインストールします。 pi@raspberrypi:~ $ sudo pip3 install smbus2 pi@raspberrypi:~ $ sudo pip3 install RPi.bme280 ライブラリが入ったら、サンプルコードで動作を確認します。 サンプルはこちらのコードを参考にしています。 import smbus2 import bme280 port = 1 #I2C1を使用するため1 address = 0x76 #BMP280のI2Cアドレス bus = smbus2.SMBus(port) #I2Cの設定 calibration_params = bme280.load_calibration_params(bus, address) #BMP280の設定値取得 data = bme280.sample(bus, address, calibration_params) #BMP280の測定値取得 print(data.timestamp) #測定時間表示 print("temperature : %s *C" % str(round(data.temperature,1))) #温度表示 print("pressure : %s hpa" % str(round(data.pressure,1))) #気圧表示 print("humidity : %s %%" % str(round(data.humidity,1))) #湿度表示 5.まとめ 今回は、ラズパイを使ったIoTシステム制作の前準備としてI2C接続とRTCの設定を行いました。 データ蓄積のためのデータベースの準備を行います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Yahoo!ショッピング商品検索(v3)を使ってJANコードから商品名を検索する

はじめに 商品の裏についているバーコードが有りますが、このバーコードはバーコードリーダーで読み取れたとして、それを使って商品名を検索できる方法はないかと考えてみました。インターネットを調べてみると手軽に使えるYahoo!ショッピング商品検索(v3)というものがあるらしいので試しに使ってみました。 REST API 使い方はとっても簡単です。GETリクエストにリクエストパラメータをつけてアクセスするとjsonが返ってきます。 URL https://shopping.yahooapis.jp/ShoppingWebService/V3/itemSearch パラメータ 指定できるパラメータはここにのってます。 今回つかうのはappid、jan_code、resultsのみです。つまり、下記のようなGETリクエストを行います。 例 GETリクエスト https://shopping.yahooapis.jp/ShoppingWebService/V3/itemSearch?appid=<app_idを入れる>&jan_code=<jan_code>&results=1 コード GETリクエスト GETリクエストの部分 import json from urllib.request import urlopen from urllib.error import URLError url = f"https://shopping.yahooapis.jp/ShoppingWebService/V3/itemSearch?appid={APPID}&jan_code={code}&results=1" try: with urlopen(url) as resp: res = json.load(resp) except URLError as err: print(err.reason, file=sys.stderr) リクエストは上のようなコードで行います。urllib.requestのurlopen()を使用しています。ドキュメントのサンプルコードを見たらwithで上のような感じで使っていましたので、それを真似てみてます。urlエラーになることは想定してないので、使うことはないかも知れないですが一応tryとexceptで例外処理も記述しています。 これだけでAPIから取得したjsonを変数に格納できます。 あとはこれを関数で記述してすこしだけ、使いやすくすればテストプログラムの完成です。というわけで出来たのがこちら サンプルプログラム search.py import sys import json from urllib.request import urlopen from urllib.error import URLError APPID = "<APPID>" def jancode_to_name(code): product_name = None url = f"https://shopping.yahooapis.jp/ShoppingWebService/V3/itemSearch?appid={APPID}&jan_code={code}&results=1" try: with urlopen(url) as resp: res = json.load(resp) except URLError as err: print(err.reason, file=sys.stderr) return None if "hits" in res and res['hits']: product_name = res["hits"][0]["name"] return product_name if len(sys.argv) != 2: sys.exit("example: search.py <jan_code>") name = jancode_to_name(sys.argv[1]) if name is None: sys.exit("Not found") print(name) こんな感じのソースコードになりました。エラーになったり存在しなかったらjancode_to_name()はNoneを返してきます。 使い方 使い方 $ python search.py 4901777273696 炭酸飲料 ペプシ リフレッシュショット サントリー 200ml 30本 1ケース のし・ギフト・サンプル各種対応不可 上のようにjan_codeを後ろにつけて実行すると商品名が表示されます。 見つからなかった時とURLErrorになったら、エラー出力にNotFoundを表示してステータスコード1で終了します。つまり取得できたときだけ0(成功)で終了すると思います(たぶん)。これはbash等で使うことを想定しています。 おわりに リクエストパラメータは他にもいろいろ使えるみたいですし、もともと検索APIですから商品の写真とかもこのやり方でとってこれるみたいです。とても便利ですね。ちなみにこのAPIを利用するにはここからデベローパー登録が必要ですが、個人用というチェックもあるので、趣味でも作業効率化でもいろいろ使ってみては面白いのではないでしょうか。M5StackやRaspberryPiでいろいろ面白いことができそうです。 この記事が誰かの参考になれば幸いです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Excelの数式が複雑すぎてインデントしたいなと思ったときにやったこと

概要 Excelの数式欄にかなりの長さの数式が埋まっており、読み解くにも修正するにもかなりの苦労が必要になってしまったので、ひとまず抜き出して解析を試みた話。 データの抜き出しには Openpyxl を利用しました。 こんな状況でした Excelの数式に入れていい文字列は75文字までとか誰か決めてくれ・・・w (計算結果の途中をどっかのセルに吐き出すとか・・・ね。) 特に Excel の IF は読みにくい =IF(A1="これこれ", "xxxx", IF(B1="あれこれ", "yyyy", "zzzz")) こんな書き方、良くしますよね・・・。 if (A1 === "これこれ") { cell = "xxxx"; } elseif (B1 === "あれこれ") { cell = "yyyy"; } else { cell = "zzzz"; } という感じなんですけど、独自関数定義するとマクロが・・・って話になりますし、リファクタリングも難しいです。なので、インデントしたりしてどうにか可読性をあげるしかないですね。 ちなみに Excel数式におけるインデントに、N()関数を加えてコメントっぽく書くことができたり、配列数式を使ってコメントっぽく書く方法もあるようです・・・ → 数式作成に便利なテクニック 今回は値の取り出し〜インデントを加えるところをやってみます もちろんマクロを使って解決する方法もありますね。 → ExcelでネストしたIf関数をVBAでインデントして分析しやすくする Python でやってみる 今回、Openpyxlを使ってやってみます。 ずばり、数式の解析は Parsing Formula を使ってできるようです。 とりあえず書いてあるのを試してみましょう。 >>> from openpyxl.formula import Tokenizer >>> tok = Tokenizer("""=IF(A1="これこれ", "xxxx", IF(B1="あれこれ", "yyyy", "zzzz"))""") >>> print("\n".join("%12s%11s%9s" % (t.value, t.type, t.subtype) for t in tok.items)) IF( FUNC OPEN A1 OPERAND RANGE =OPERATOR-INFIX "これこれ" OPERAND TEXT , SEP ARG WHITE-SPACE "xxxx" OPERAND TEXT , SEP ARG WHITE-SPACE IF( FUNC OPEN B1 OPERAND RANGE =OPERATOR-INFIX "あれこれ" OPERAND TEXT , SEP ARG WHITE-SPACE "yyyy" OPERAND TEXT , SEP ARG WHITE-SPACE "zzzz" OPERAND TEXT ) FUNC CLOSE ) FUNC CLOSE なるほど。先頭からそれぞれのパーツが関数(開始・終了)なのか、変数なのか等々に分解してくれるようだ。 ということは関数が開始したら改行して、次の行にはインデントをつけ、関数が終了するときにインデントを減らしてから改行していけばよいということですね。 わかりやすさのためにインデントを可視化して書いてみる from openpyxl.formula import Tokenizer # あとでindent_charはもちろんスペースに直すよ def parse(formula, indent_char = "_"): # 最終的に文字列として結合して返す result = "" tok = Tokenizer(formula) # インデント数 n = 0 # 直前で処理したトークン last = None for t in tok.items: if t.type == "FUNC": if t.subtype == "OPEN": if last is not None and (last.type == "FUNC" and last.subtype == "OPEN"): n += 2 result += indent_char * n + t.value else: result += t.value result += "\n" else: # function close。インデント数を戻す n -= 2 result += "\n" + indent_char * n + t.value else: # それ以外は単純結合。直前が関数の場合はインデント if last is not None and (last.type == "FUNC" and last.subtype == "OPEN"): n += 2 result += indent_char * n + t.value else: result += t.value last = t return result s = """=IF(A1="これこれ", "xxxx", IF(B1="あれこれ", "yyyy", "zzzz"))""" print(parse(s)) IF( __A1="これこれ", "xxxx", IF( ____B1="あれこれ", "yyyy", "zzzz" __) ) うん。これで良さそう。 あとはExcelの指定したセル範囲とかを渡して wb = load_workbook(filename, data_only = False) sheet_name = "Sheet1" cell_range = "A2:C2" for line in wb[sheet_name][cell_range]: for cell in line: # formula のみを抽出 if cell.data_type == "f": f = parse(cell.value) # cell.coordinateには「A1」などの表現が入る with open(cell.coordinate + ".txt", mode='w') as fl: fl.write(f) こんな感じにすれば、数式が埋まっているセルだけ、A2.txt, C2.txtのようにインデント済のテキストとして吐き出せます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pythonで楽しくtoio非同期制御!

初めに 初めまして、大学院生のヨッシーです。初めてのQiita投稿なので不慣れながらも頑張ります! 遅ばせながら、最近になってtoio買いました。ちょこちょこ動く姿が可愛いんですよねぇ。 ところで、最近toioの技術仕様書も公開されたということで、試しに私のMacBookからBLE通信で操作を試したのですが、、、、 操作が難しい。 Characteristics?リトルエンディアン?などなど、バイト配列でtoioにデータを送り込むみたいですが、もっと直感的にtoioを操作したい! ということで、Pythonで直感的なtoio操作のAPIを作成したのでこちらで紹介していきます。 前準備 こちらのレポジトリを基に話を展開していきます。 クローン後、該当ディレクトリにて$ pip install -e .を実行してください(場合によってはsudoで)。 動作環境 macOS Big Sur (M1 chip) Python 3.8.5 bleak 0.11.0 まずは接続してみる discover_toios まずはご自身のPCがtoioを認識するかのテストをします。ここでは、discover_toiosというmethodを使います。試しに、toioが見つからない場合、一つ見つかった場合、二つ見つかった場合を示しています。 tmp.py import asyncio from toio_API.utils.general import discover_toios if __name__ == '__main__': toio_addresses = asyncio.run(discover_toios()) 出力結果: $ python tmp.py [INFO] [2021-04-27 10:20:58,068] [general.py:49] No toio discovered :( $ python tmp.py [INFO] [2021-04-27 10:21:09,650] [general.py:47] 1 toio discovered: ['33139358-E12D-45F8-9B83-A23EBC3CDD58'] $ python tmp.py [INFO] [2021-04-27 10:21:25,622] [general.py:47] 2 toio discovered: ['B62DBD30-1D16-4796-A60F-E76903A3BEF0', '33139358-E12D-45F8-9B83-A23EBC3CDD58'] BLE通信が可能なtoioのBLE addressをリストで返します(これ意外と便利)。 create_toios 次に見つけたtoioに名前をつけてプログラムで扱いやすくするためにregisterしていきます。 ここではcreate_toiosというmethodを使います。 tmp.py import asyncio from toio_API.utils.general import create_toios, discover_toios if __name__ == '__main__': toio_addresses = asyncio.run(discover_toios()) toios = create_toios(toio_addresses=toio_addresses) 出力結果: $ python tmp.py [INFO] [2021-04-27 10:27:12,504] [general.py:47] 2 toio discovered: ['B62DBD30-1D16-4796-A60F-E76903A3BEF0', '33139358-E12D-45F8-9B83-A23EBC3CDD58'] [INFO] [2021-04-27 10:27:12,506] [general.py:30] 2 Successfully registered the toio: ['toio_0', 'toio_1'] この時、toioに名前をつけることができます!デフォルトではtoio_#ですが、以下のように任意の名前をつけてあげることもできます。 tmp.py import asyncio from toio_API.utils.general import create_toios, discover_toios if __name__ == '__main__': toio_addresses = asyncio.run(discover_toios()) toios = create_toios(toio_addresses=toio_addresses, toio_names=['Yoshi', 'Moto']) 出力結果: $ python tmp.py [INFO] [2021-04-27 10:27:43,762] [general.py:47] 2 toio discovered: ['B62DBD30-1D16-4796-A60F-E76903A3BEF0', '33139358-E12D-45F8-9B83-A23EBC3CDD58'] [INFO] [2021-04-27 10:27:43,764] [general.py:30] 2 Successfully registered the toio: ['Yoshi', 'Moto'] やっぱり名前つけてあげたほうが愛着湧きますよねぇ笑 connect ・ disconnect ここからは非同期処理を実際に扱っていきます。 toioをBLE通信で接続するmethodであるconnect、及び接続解除するmethodのdisconnectはasync defで実装されているため、複数体のtoioを扱う場合は以下のように新しい関数connect_disconnect()を作成します。 この関数は複数toioを一秒間だけ接続し、その後接続解除しています。 tmp.py import asyncio from toio_API.utils.general import connect, create_toios, disconnect, discover_toios async def connect_disconnect(toios): await asyncio.gather(*[connect(toio) for toio in toios]) await asyncio.sleep(1) await asyncio.gather(*[disconnect(toio) for toio in toios]) if __name__ == '__main__': toio_addresses = asyncio.run(discover_toios()) toios = create_toios(toio_addresses=toio_addresses, toio_names=['Yoshi', 'Moto']) asyncio.run(connect_disconnect(toios)) 出力結果: $ python tmp.py [INFO] [2021-04-27 11:19:50,834] [general.py:47] 2 toio discovered: ['33139358-E12D-45F8-9B83-A23EBC3CDD58', 'B62DBD30-1D16-4796-A60F-E76903A3BEF0'] [INFO] [2021-04-27 11:19:50,836] [general.py:30] 2 Successfully registered the toio: ['Yoshi', 'Moto'] [INFO] [2021-04-27 11:19:52,551] [general.py:62] [Yoshi] Successfully connected the toio! [INFO] [2021-04-27 11:19:53,069] [general.py:62] [Moto] Successfully connected the toio! [INFO] [2021-04-27 11:19:54,108] [general.py:79] [Yoshi] Successfully disonnected the toio! [INFO] [2021-04-27 11:19:54,171] [general.py:79] [Moto] Successfully disonnected the toio! 無事に接続、接続解除ができていることが確認できますね。 動かしてみる 最後にtoioに一秒間の回転運動をしてもらいます。 これまでの手順通りtoioを接続した後に、toioのモーターをtoio.motorを使って制御するコマンドを入力します。ここでは最もシンプルなtoio.motor.controlというモーター駆動コマンドを実行します。デフォルトで回転運動します。 tmp.py import asyncio from toio_API.utils.general import connect, create_toios, disconnect, discover_toios async def kaiten(toios): await asyncio.gather(*[connect(toio) for toio in toios]) await asyncio.gather(*[toio.motor.control() for toio in toios]) await asyncio.sleep(1) await asyncio.gather(*[disconnect(toio) for toio in toios]) if __name__ == '__main__': toio_addresses = asyncio.run(discover_toios()) toios = create_toios(toio_addresses=toio_addresses, toio_names=['Yoshi', 'Moto']) asyncio.run(kaiten(toios)) 簡単ですね、一行加えるだけで回転運動を非同期でさせることができました。 デモ動画も用意したので是非確認してみてください! 最後に 今回は自作APIでtoioをpythonで簡単に非同期制御することを目標に進めてきました。 無事できてよかったです笑 モーター以外にも他にも様々な機能のAPIも合わせて実装したのでこれから時間があればじゃんじゃん紹介していけたらと思います! 参考サイト toio公式 toio技術仕様書 toio を Mac + Python で制御できるライブラリつくった Pythonライブラリ bleakでWindows10/macOS/Linux上でtoioコア キューブを動かしてみる toioをRaspberry Piで制御する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pythonで楽しくtoio非同期制御!(その1)

初めに 初めまして、大学院生のヨッシーです。初めてのQiita投稿なので不慣れながらも頑張ります! 遅ばせながら、最近になってtoio買いました。ちょこちょこ動く姿が可愛いんですよねぇ。 ところで、最近toioの技術仕様書も公開されたということで、試しに私のMacBookからBLE通信で操作を試したのですが、、、、 操作が難しい。 Characteristics?リトルエンディアン?などなど、バイト配列でtoioにデータを送り込むみたいですが、もっと直感的にtoioを操作したい! ということで、Pythonで直感的なtoio操作のAPIを作成したのでこちらで紹介していきます。 前準備 こちらのレポジトリを基に話を展開していきます。 クローン後、該当ディレクトリにて$ pip install -e .を実行してください(場合によってはsudoで)。 動作環境 macOS Big Sur (M1 chip) Python 3.8.5 bleak 0.11.0 まずは接続してみる discover_toios まずはご自身のPCがtoioを認識するかのテストをします。ここでは、discover_toiosというmethodを使います。試しに、toioが見つからない場合、一つ見つかった場合、二つ見つかった場合を示しています。 tmp.py import asyncio from toio_API.utils.general import discover_toios if __name__ == '__main__': toio_addresses = asyncio.run(discover_toios()) 出力結果: $ python tmp.py [INFO] [2021-04-27 10:20:58,068] [general.py:49] No toio discovered :( $ python tmp.py [INFO] [2021-04-27 10:21:09,650] [general.py:47] 1 toio discovered: ['33139358-E12D-45F8-9B83-A23EBC3CDD58'] $ python tmp.py [INFO] [2021-04-27 10:21:25,622] [general.py:47] 2 toio discovered: ['B62DBD30-1D16-4796-A60F-E76903A3BEF0', '33139358-E12D-45F8-9B83-A23EBC3CDD58'] BLE通信が可能なtoioのBLE addressをリストで返します(これ意外と便利)。 create_toios 次に見つけたtoioに名前をつけてプログラムで扱いやすくするためにregisterしていきます。 ここではcreate_toiosというmethodを使います。 tmp.py import asyncio from toio_API.utils.general import create_toios, discover_toios if __name__ == '__main__': toio_addresses = asyncio.run(discover_toios()) toios = create_toios(toio_addresses=toio_addresses) 出力結果: $ python tmp.py [INFO] [2021-04-27 10:27:12,504] [general.py:47] 2 toio discovered: ['B62DBD30-1D16-4796-A60F-E76903A3BEF0', '33139358-E12D-45F8-9B83-A23EBC3CDD58'] [INFO] [2021-04-27 10:27:12,506] [general.py:30] 2 Successfully registered the toio: ['toio_0', 'toio_1'] この時、toioに名前をつけることができます!デフォルトではtoio_#ですが、以下のように任意の名前をつけてあげることもできます。 tmp.py import asyncio from toio_API.utils.general import create_toios, discover_toios if __name__ == '__main__': toio_addresses = asyncio.run(discover_toios()) toios = create_toios(toio_addresses=toio_addresses, toio_names=['Yoshi', 'Moto']) 出力結果: $ python tmp.py [INFO] [2021-04-27 10:27:43,762] [general.py:47] 2 toio discovered: ['B62DBD30-1D16-4796-A60F-E76903A3BEF0', '33139358-E12D-45F8-9B83-A23EBC3CDD58'] [INFO] [2021-04-27 10:27:43,764] [general.py:30] 2 Successfully registered the toio: ['Yoshi', 'Moto'] やっぱり名前つけてあげたほうが愛着湧きますよねぇ笑 connect ・ disconnect ここからは非同期処理を実際に扱っていきます。 toioをBLE通信で接続するmethodであるconnect、及び接続解除するmethodのdisconnectはasync defで実装されているため、複数体のtoioを扱う場合は以下のように新しい関数connect_disconnect()を作成します。 この関数は複数toioを一秒間だけ接続し、その後接続解除しています。 tmp.py import asyncio from toio_API.utils.general import connect, create_toios, disconnect, discover_toios async def connect_disconnect(toios): await asyncio.gather(*[connect(toio) for toio in toios]) await asyncio.sleep(1) await asyncio.gather(*[disconnect(toio) for toio in toios]) if __name__ == '__main__': toio_addresses = asyncio.run(discover_toios()) toios = create_toios(toio_addresses=toio_addresses, toio_names=['Yoshi', 'Moto']) asyncio.run(connect_disconnect(toios)) 出力結果: $ python tmp.py [INFO] [2021-04-27 11:19:50,834] [general.py:47] 2 toio discovered: ['33139358-E12D-45F8-9B83-A23EBC3CDD58', 'B62DBD30-1D16-4796-A60F-E76903A3BEF0'] [INFO] [2021-04-27 11:19:50,836] [general.py:30] 2 Successfully registered the toio: ['Yoshi', 'Moto'] [INFO] [2021-04-27 11:19:52,551] [general.py:62] [Yoshi] Successfully connected the toio! [INFO] [2021-04-27 11:19:53,069] [general.py:62] [Moto] Successfully connected the toio! [INFO] [2021-04-27 11:19:54,108] [general.py:79] [Yoshi] Successfully disonnected the toio! [INFO] [2021-04-27 11:19:54,171] [general.py:79] [Moto] Successfully disonnected the toio! 無事に接続、接続解除ができていることが確認できますね。 動かしてみる 最後にtoioに一秒間の回転運動をしてもらいます。 これまでの手順通りtoioを接続した後に、toioのモーターをtoio.motorを使って制御するコマンドを入力します。ここでは最もシンプルなtoio.motor.controlというモーター駆動コマンドを実行します。デフォルトで回転運動します。 tmp.py import asyncio from toio_API.utils.general import connect, create_toios, disconnect, discover_toios async def kaiten(toios): await asyncio.gather(*[connect(toio) for toio in toios]) await asyncio.gather(*[toio.motor.control() for toio in toios]) await asyncio.sleep(1) await asyncio.gather(*[disconnect(toio) for toio in toios]) if __name__ == '__main__': toio_addresses = asyncio.run(discover_toios()) toios = create_toios(toio_addresses=toio_addresses, toio_names=['Yoshi', 'Moto']) asyncio.run(kaiten(toios)) 簡単ですね、一行加えるだけで回転運動を非同期でさせることができました。 デモ動画も用意したので是非確認してみてください! 最後に 今回は自作APIでtoioをpythonで簡単に非同期制御することを目標に進めてきました。 無事できてよかったです笑 モーター以外にも他にも様々な機能のAPIも合わせて実装したのでこれから時間があればじゃんじゃん紹介していけたらと思います! 続き その他のtoio.motorのコマンド紹介 その他諸々 参考サイト toio公式 toio技術仕様書 toio を Mac + Python で制御できるライブラリつくった Pythonライブラリ bleakでWindows10/macOS/Linux上でtoioコア キューブを動かしてみる toioをRaspberry Piで制御する
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

rviz上でLidarの光線を可視化するスクリプト

概要 VisualizationMarkerの練習のためにLidarの光線を可視化するスクリプトを作ったので自分用にメモ。 前提 velodyne_simulatorではなぜかfor文のところでエラーが出てうまく行かない。 手持ちのLidarだとうまく行くので、velodyne_simulatorのトピック形式がおかしいのかもしれない。 参考 実装 PointCloud2形式のトピックを受信して、Lidarの原点と各点群間を直線で描画する。 #!/usr/bin/python # -*- coding: utf-8 -*- from __future__ import print_function import rospy from visualization_msgs.msg import * from sensor_msgs.msg import PointCloud2 import sensor_msgs.point_cloud2 as pc2 from geometry_msgs.msg import Point import tf2_ros def callback(cloud, pub): tfBuffer = tf2_ros.Buffer() listerner = tf2_ros.TransformListener(tfBuffer) source_id = cloud.header.frame_id dest_id = "lidar_link" while True: try: trans = tfBuffer.lookup_transform(source_id, dest_id, rospy.Time(0), rospy.Duration(1.0)) except (tf2_ros.LookupException, tf2_ros.ConnectivityException, tf2_ros.ExtrapolationException): print("WARNING: tf %s to %s not found." % (source_id, dest_id)) continue marker = Marker() marker.header = cloud.header marker.ns = "ray" marker.id = 0 marker.type = Marker.LINE_LIST # LINE_STRIP/LINE_LIST markers use only the x component of scale, for the line width marker.scale.x = 0.001 marker.color.b = 1.0 marker.color.a = 1.0 origin_point = Point() origin_point.x = trans.transform.translation.x origin_point.y = trans.transform.translation.y origin_point.z = trans.transform.translation.z for p in pc2.read_points(cloud, field_names=("x", "y", "z"), skip_nans=True): target_point = Point() target_point.x = p[0] target_point.y = p[1] target_point.z = p[2] marker.points.append(origin_point) marker.points.append(target_point) pub.publish(marker) break if __name__ == "__main__": rospy.init_node("visualize_ray") pub = rospy.Publisher("/visualize_ray/maker", Marker, queue_size=1) sub = rospy.Subscriber("lidar scan topic", PointCloud2, callback, pub) rospy.spin()
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

JavaのBigDecimalの割り算の丸め処理をPythonに書き換える

最近Javaで書かれたバッチをPythonに書き換えている。 Javaで正確な丸めを行うためにBigDecimalを使ったコードがある。 それをPythonに書き換える際に対応するメソッドがなく困った。 本記事では対応策をまとめる。 Java側 Javaのコードが以下のようだとする。 import java.math.BigDecimal; import java.math.RoundingMode; class BigDecimalDivideTest { public static void main(String[] args) { BigDecimal someValue = BigDecimal.valueOf(3215); BigDecimal BD_100 = BigDecimal.valueOf(1000); int SCALE_2 = 2; System.out.println(someValue.divide(BD_100, SCALE_2, RoundingMode.HALF_UP)); // 3.22が表示される } } Python側 from decimal import * some_value = Decimal('3215') bd_100 = Decimal('1000') scale_2 = 2 divided_value = some_value / bd_100 scaled_decimal = Decimal(str(10 ** - scale_2)) # => Decimal('0.01')になる。 # 丸め処理にはquantizeメソッドを使う divided_value.quantize(scaled_decimal, rounding=ROUND_HALF_UP) # => Decimal('3.22') 説明 Pythonにおける、JavaのBigDecimalに対応するライブラリはdecimalである。 https://docs.python.org/ja/3/library/decimal.html だが decimal の divide メソッドでは、Javaのようにスケールや丸めについて引数を取るものがない。 なので、スケール処理と丸めはquantizeで割り算のあとに行う。 なお、quantizeでエラーが出る場合がある。 from decimal import * getcontext().prec = 2 # 追加 some_value = Decimal('3215') bd_100 = Decimal('1000') scale_2 = 2 divided_value = some_value / bd_100 scaled_decimal = Decimal(str(10 ** - scale_2)) divided_value.quantize(scaled_decimal, rounding=ROUND_HALF_UP) # => decimal.InvalidOperation 例外が発生する https://docs.python.org/ja/3/library/decimal.html#decimal.Decimal.quantize 他の操作と違い、打ち切り(quantize)操作後の係数の長さが精度を越えた場合には、 InvalidOperation がシグナルされます。 getcontext().prec = 2を追加した上でquantizeを行うと、quantize結果が数値全体で2桁(3.2とか)でないとエラーになる。 今回はquantize結果は3.22であり結果が3桁になるので、InvalidOperationが出る。 なんで書こうと思ったか Pythonのドキュメントの一番上で以下のようなコードが書いてある。 from decimal import * getcontext().prec = 6 Decimal(1) / Decimal(7) # => Decimal('0.142857') これを見て、私は桁数を指定するにはgetcontext().precを指定すればいいのかとミスリードした。 precは数値全体の桁数の話なので、prec = 6としても小数点以下6桁を保証してくれるわけではない。 例えば上記の割り算の対象数字が大きかったとすると、以下のようになる。 from decimal import * getcontext().prec = 6 print(Decimal(10000000) / Decimal(7)) # => Decimal('1.42857E+6') print(float(Decimal(10000000) / Decimal(7))) # floatに変換すると1428570.0 # prec = 有効桁数は6なので、142857までの6桁までは計算結果が保持されるがそれ以降は0に 参考 なぜBigDecimalを使わなければならないのか | Java好き BigDecimalを使う理由が理解できた。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

TGAN, CTGANの使い方メモ

何をするものか GANでテーブルデータをaugmentationしてやろうというものです。 GANが学習できるぐらいデータ量があるならあんまり効かないんじゃないかという話もありますがこちらの記事によるとそこそこ効いてくれるようです。 https://qiita.com/jovyan/items/c41ab61a6b04e9a6e4df TGAN github repository https://github.com/sdv-dev/TGAN 1. インストール pipで入ります pipでインストール pip install tgan 2. 使い方 2-1. データの準備 付属しているサンプルデータでやってみます from tgan.data import load_demo_data data, continuous_columns = load_demo_data('census') print(data.shape) data.head(3) 2-2. モデルをつくる データは連続値と離散値の2つに分けて扱われるので、どの列を連続値として扱ってほしいか指定します。 from tgan.model import TGANModel tgan = TGANModel(continuous_columns) 2-3. 学習する fit()すればGANモデルの学習がスタートしますが、データに欠損値やinfがあるとエラーになるので適当な前処理が必要です。このデータは1行だけ欠損値が入ったデータがあるのでdropna()して学習してみます。 tgan.fit(data.dropna(axis=0)) 2-4. データを生成する あとはいくつ生成するか指定してGANモデルにデータを作ってもらうだけです num_samples = 1000 samples = tgan.sample(num_samples) samples.head(3) 2-5. モデルの保存 作ったGANモデルは以下のようにして保存できます 保存する model_path = 'models/mymodel.pkl' tgan.save(model_path) 上書きを有効にして保存する model_path = 'models/mymodel.pkl' tgan.save(model_path, force=True) 2-6. モデルの読み込み new_tgan = TGANModel.load(model_path) new_samples = new_tgan.sample(num_samples) new_samples.head(3) CTGAN TGANの改良版です github repository https://github.com/sdv-dev/CTGAN 1. インストール pipで入ります pip install ctgan 2. 使い方 2-1. 学習~生成 TGANとは逆で離散値列のlistを渡して指定します。 from ctgan import CTGANSynthesizer from ctgan import load_demo data = load_demo() # Names of the columns that are discrete discrete_columns = [ 'workclass', 'education', 'marital-status', 'occupation', 'relationship', 'race', 'sex', 'native-country', 'income' ] ctgan = CTGANSynthesizer(epochs=10) ctgan.fit(data, discrete_columns) # Synthetic copy samples = ctgan.sample(1000) 2-2. モデルの保存 model.save('my_model.pkl') 2-3. モデルの読み込み ctgan2 = CTGANSynthesizer().load('my_model.pkl') ctgan2
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Python+Selenium+BeautifulSoupでSBIベネフィットシステムズの資産状況データを解析しCSVに書き出す

PythonとSeleniumとBeautifulSoupを使って、SBIベネフィットシステムズのサイトにログインして資産状況データを取得(CSVダウンロード)する方法を試してみました。 サンプルコード全文も記事の後半に載せているので参考になれば幸いです。そしてもっと上手いやり方ご存知の方いらっしゃったらぜひ教えてください^^ ※2021/04/27時点の情報です。 環境 Windows 10 Python 3.8 Selenium 3.141.0 はじめに ログインまでの部分については下記記事を参考にしてみてください。 なお、上記記事ではインポートしていないライブラリがいくつかあります。以下もインポート必要になりますので追加しておきましょう。 import os import csv from bs4 import BeautifulSoup CSVダウンロード機能がない! これまで、複数の金融機関サイトで明細データをダウンロードするサンプルコードを書いてきました。大抵はCSVダウンロード機能を提供しているので、Seleniumでダウンロードボタンのクリック操作を再現させるだけで簡単にダウンロードできます。 しかし、残念ながらSBIベネフィットシステムズのサイトでは、ダウンロードする機能がありませんでした。。 BeautifulSoupでHTMLタグを解析する そこで、BeautifulSoupというHTMLを解析することができるスクレイピング用のライブラリを使って欲しいデータを取得することにします。 対象画面まで遷移する まず、SBIベネフィットシステムズのログイン後TOP画面から、資産状況画面まで遷移させてみましょう。 ◆TOP画面 画面上部にあるメニューの中から「資産状況」リンクをクリックさせることで遷移できます。 # 資産状況画面遷移 browser.find_element_by_id("D_Header1_uscD_CategoryMenu1_rptFunctionMenuTable__ctl2_btnMenuData").click() # ページロード完了まで待機 WebDriverWait(browser, 10).until( ec.presence_of_element_located((By.ID, "palsyouhinbetu")) ) print("資産状況画面遷移成功") ◆資産状況画面 遷移すると、資産状況欄に保有している商品の一覧が表示されます。商品一覧はtableタグで構築されているので、今回はこのtable要素を解析してデータを取得します。 table要素の解析方法 table要素を抜き出す BeautifulSoupを使って要素解析するには、HTMLソースを取得する必要があります。BeautifulSoupの参考書等ではRequestsというライブラリを使って取得するのが一般的のようですが、今回は既にSeleniumを使って画面遷移していますので、SeleniumのWebDriverから取得します。WebDriverのpage_source()メソッドを使えばHTMLソースを取得できます。 # 資産一覧テーブル取得 html = browser.page_source soup = BeautifulSoup(html, "html.parser") HTMLソースを取得したら、今度はお目当てのtable要素を取得します。tableタグにはidが割り当てられているので、BeautifulSoupのfind()メソッドの引数にidを指定することで取得可能です。 table = soup.find(id="grdSyouhinzangaku") tr_list = table.find_all("tr") また、商品は各行(trタグ)に格納されているので、trタグの一覧をfind_all()メソッドを使って取得しておきます。 tableの構成を確認する ここでひとまず、取得したtable要素の全体像を確認しておきましょう。 (※下記サンプルの金額はテキトーに加工した値です) <table cellspacing="0" cellpadding="4" rules="all" bordercolor="#CCCCCC" border="2" id="grdSyouhinzangaku" style="border-color:#CCCCCC;border-width:2px;border-style:solid;border-collapse:collapse;"> <tbody> <tr class="tableHeader" align="center" valign="middle"> <td>商品タイプ</td> <td><span class="prod-formal">運用商品名</span><span class="f">(略称)</span></td> <td>時価単価<br><span class="unit-txt">(1万口当り)</span></td> <td>残高数量</td> <td>資産残高</td> <td>購入金額</td> <td>損益<br>損益率</td> <td>&nbsp;</td> </tr> <tr class="even-row"> <td align="center" style="width:100px;"> <label class="balanceIcon" style="BACKGROUND-COLOR:#ff99cc"> 国内株式 </label> </td> <td align="left" style="width:225px;"> <a href="javascript:subSyohinNew('../Knowledge/JP_D_Knowledge_InvestTrust_Inquiry.aspx?SCD=9200109227&amp;CCD=01')"> <span class="prod-formal">eMAXIS Slim 国内株式(TOPIX)</span> <span class="prod-abbrv">(eMAXIS Slim 国内株式(TOPIX))</span> </a> </td> <td align="right" style="width:79px;">13,576<span class="unit">円</span></td> <td align="right" style="width:89px;">129,790<span class="unit">口</span></td> <td align="right" style="width:79px;">176,202<span class="unit">円</span></td> <td align="right" style="width:79px;">132,538<span class="unit">円</span></td> <td align="right" style="width:79px;">43,664<span class="unit">円</span><br>32.9<span class="unit">%</span></td> <td align="right" style="width:79px;"></td> </tr> <tr class="odd-row"> <td align="center" style="width:100px;"> <label class="balanceIcon" style="BACKGROUND-COLOR:#ff00ff">内外株式</label> </td> <td align="left" style="width:225px;"> <a href="javascript:subSyohinNew('../Knowledge/JP_D_Knowledge_InvestTrust_Inquiry.aspx?SCD=9200196387&amp;CCD=01')"> <span class="prod-formal">ひふみ年金</span> <span class="prod-abbrv">(ひふみ年金)</span> </a> </td> <td align="right" style="width:79px;">18,729<span class="unit">円</span></td> <td align="right" style="width:89px;">96,108<span class="unit">口</span></td> <td align="right" style="width:79px;">180,000<span class="unit">円</span></td> <td align="right" style="width:79px;">132,538<span class="unit">円</span></td> <td align="right" style="width:79px;">47,462<span class="unit">円</span><br>35.8<span class="unit">%</span></td> <td align="right" style="width:79px;"></td> </tr> <<< 以下略 >>> </tbody> </table> 解析にあたってポイントとなる点を列挙しました。 「商品名」と「略称」がひとつのtdタグ内に存在している → 「商品名」だけ抜き出したい タイトル行のうち、「損益」と「損益率」がひとつのtdタグ内に存在している → 列を分割して保存したい 金額や口数は単位がついている → 単位は削除したい(損益率だけは逆に残しておいたほうがわかりやすそう) このように、各データを微妙に加工しながら取り込む必要があります。 1行ずつ解析しながらCSV出力用データを作成 では、先ほど最後に取得したtr_listを1行ずつ読み込みながらCSV出力用のデータを作っていきましょう。 # CSV出力用データ data = [] for i, tr in enumerate(tr_list): row_data = [] if i == 0: # ヘッダー行の処理 # 損益と損益率を列分割するので自前でヘッダー行を用意する row_data.extend(["商品タイプ", "運用商品名", "時価単価", "残高数量", "資産残高", "購入金額", "損益", "損益率(%)"]) data.append(row_data) continue # td要素取得 td_list = tr.find_all("td") # 商品タイプ row_data.append(td_list[0].text.strip()) # 運用商品名(略称は削除) row_data.append(td_list[1].find(class_="prod-formal").text.strip()) # 時価単価(単位は削除) td_txt = td_list[2].text.strip() row_data.append(td_txt[:td_txt.find('円')]) # 残高数量(単位は削除) td_txt = td_list[3].text.strip() row_data.append(td_txt[:td_txt.find('口')]) # 資産残高(単位は削除) td_txt = td_list[4].text.strip() row_data.append(td_txt[:td_txt.find('円')]) # 購入金額(単位は削除) td_txt = td_list[5].text.strip() row_data.append(td_txt[:td_txt.find('円')]) # 損益(単位は削除)、損益率 td_txt = td_list[6].text.strip() row_data.append(td_txt[:td_txt.find('円')]) # 円の前 row_data.append(td_txt[td_txt.find('円') + 1:]) # 円の後 data.append(row_data) ヘッダー行のみ、if文で分岐させてデータ作成しています。 あとはtrの要素からtd要素を取得しtd_listに格納します。そして添字で1要素ずつ指定しながら必要な加工・修正を加えていきます。 CSVファイルに書き出し 最後に、作成したデータをCSVファイルに書き出します。書き出したら忘れずにclose()しておきましょう。 # ダウンロード先&ファイル名 # パス、ファイル名は任意な値に変更してください output_file_name = "../dl-data/result_sbi.csv" if os.path.exists(output_file_name): # ファイルが存在する時は削除 os.remove(output_file_name) # CSVファイルに書き出し with open(output_file_name, 'w') as file: w = csv.writer(file, lineterminator='\n') w.writerows(data) file.close() 以上、Python+Selenium+BeautifulSoupを使ってSBIベネフィットシステムズの資産状況データを解析しCSVに書き出す方法でした! サンプルコード全文 # # SBIベネフィットシステムズサイトへログインして資産状況を取得 # import os import csv import json from bs4 import BeautifulSoup from selenium.webdriver import Firefox, FirefoxOptions from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as ec # 設定ファイルを取得 login_info = json.load(open("login_info.json", "r", encoding="utf-8")) # ログインサイト名 site_name = "ideco_sbi" # ログイン画面URL url_login = login_info[site_name]["url"] # ユーザー名とパスワードの指定 USER = login_info[site_name]["id"] PASS = login_info[site_name]["pass"] # Firefoxのヘッドレスモードを有効にする options = FirefoxOptions() options.add_argument('--headless') # Firefoxを起動する browser = Firefox(options=options) # ログイン画面取得 browser.get(url_login) # 入力 e = browser.find_element_by_id("txtUserID") e.clear() e.send_keys(USER) e = browser.find_element_by_id("txtPassword") e.clear() e.send_keys(PASS) # ログイン browser.find_element_by_id("btnLogin").click() # ページロード完了まで待機 WebDriverWait(browser, 10).until( ec.presence_of_element_located((By.ID, "D_Header1_lblEmployeeName")) ) print("ログイン成功") # ログインできたか確認(画面キャプチャ取る) # browser.save_screenshot("../screenshots/ideco_sbi/home.png") # 資産状況画面遷移 browser.find_element_by_id("D_Header1_uscD_CategoryMenu1_rptFunctionMenuTable__ctl2_btnMenuData").click() # ページロード完了まで待機 WebDriverWait(browser, 10).until( ec.presence_of_element_located((By.ID, "palsyouhinbetu")) ) print("資産状況画面遷移成功") # 資産一覧テーブル取得 html = browser.page_source soup = BeautifulSoup(html, "html.parser") table = soup.find(id="grdSyouhinzangaku") tr_list = table.find_all("tr") # CSV出力用データ data = [] for i, tr in enumerate(tr_list): row_data = [] if i == 0: # ヘッダー行の処理 # 損益と損益率を列分割するので自前でヘッダー行を用意する row_data.extend(["商品タイプ", "運用商品名", "時価単価", "残高数量", "資産残高", "購入金額", "損益", "損益率(%)"]) data.append(row_data) continue # td要素取得 td_list = tr.find_all("td") # 商品タイプ row_data.append(td_list[0].text.strip()) # 運用商品名(略称は削除) row_data.append(td_list[1].find(class_="prod-formal").text.strip()) # 時価単価(単位は削除) td_txt = td_list[2].text.strip() row_data.append(td_txt[:td_txt.find('円')]) # 残高数量(単位は削除) td_txt = td_list[3].text.strip() row_data.append(td_txt[:td_txt.find('口')]) # 資産残高(単位は削除) td_txt = td_list[4].text.strip() row_data.append(td_txt[:td_txt.find('円')]) # 購入金額(単位は削除) td_txt = td_list[5].text.strip() row_data.append(td_txt[:td_txt.find('円')]) # 損益(単位は削除)、損益率 td_txt = td_list[6].text.strip() row_data.append(td_txt[:td_txt.find('円')]) # 円の前 row_data.append(td_txt[td_txt.find('円') + 1:]) # 円の後 data.append(row_data) # ダウンロード先&ファイル名 output_file_name = "../dl-data/result_sbi.csv" if os.path.exists(output_file_name): # ファイルが存在する時は削除 os.remove(output_file_name) # CSVファイルに書き出し with open(output_file_name, 'w') as file: w = csv.writer(file, lineterminator='\n') w.writerows(data) file.close() # 処理終了 browser.quit() print("=== All done! ===")
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

pythonでgnuradio その7

概要 pythonでgnuradioやってみた。 AM変調を録音した、wavファイル読み込んでAM復調して、聞く。 信号は、440hzのサイン波、搬送波は、5KHZ。 サンプルコード from gnuradio import gr, blocks, analog from gnuradio import audio class my_top_block(gr.top_block): def __init__(self): gr.top_block.__init__(self) samp_rate = 32000 self.blocks_wavfile_source_0 = blocks.wavfile_source('a2.wav', True) self.blocks_magphase_to_complex_0 = blocks.magphase_to_complex(1) self.blocks_add_const_vxx_0 = blocks.add_const_vff((2, )) self.audio_sink_0 = audio.sink(samp_rate, '', True) self.analog_am_demod_cf_0 = analog.am_demod_cf(channel_rate = 32000, audio_decim = 1, audio_pass = 5000, audio_stop = 5500, ) self.connect((self.analog_am_demod_cf_0, 0), (self.audio_sink_0, 0)) self.connect((self.blocks_add_const_vxx_0, 0), (self.blocks_magphase_to_complex_0, 0)) self.connect((self.blocks_add_const_vxx_0, 0), (self.blocks_magphase_to_complex_0, 1)) self.connect((self.blocks_magphase_to_complex_0, 0), (self.analog_am_demod_cf_0, 0)) self.connect((self.blocks_wavfile_source_0, 0), (self.blocks_add_const_vxx_0, 0)) if __name__ == '__main__': try: my_top_block().run() except KeyboardInterrupt: pass 以上。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DataFrameの1番楽で美しい作成方法

今回はPandas初心者に向けて「結局どの書き方が一番美しいの??」という疑問を解消する。 〜feat.独断と偏見〜 パターン1 import pandas as pd import numpy as np a0 = np.array([1,2,3,4,5]) a1 = np.array(['北海道','秋田','岩手','沖縄','鹿児島']) IKITEE = pd.DataFrame({ '数字':a0, '場所':a1, }) print(IKITEE) パターン2 import pandas as pd import numpy as np IKITEE = pd.DataFrame( {'数字':[1,2,3,4,5], '場所':['北海道','秋田','岩手','沖縄','鹿児島']}, columns = ['数字','場所']) print(IKITEE) こんな感じです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

平行座標プロット

平行座標プロット 線の交差が少ない:正の相関 線の交差が多い:負の相関 イメージが湧かないのでとりあえず描いてみる。 matplotlibでは平行座標プロットの描画は組み合わせで作るしかないようです。 plotlyだと直接平行座標プロットを描画できるのでplotlyを使います。 #使うライブラリなど import pandas as pd import matplotlib.pyplot as plt import plotly.express as px from sklearn.datasets import load_iris import seaborn as sns 量的変数の平行座標プロット てきとうな例 身長と体重の量的変数2つ。 10人想定して、 BMIの式にほぼ当てはまる、身長高いほど体重が高いという正の相関を8人。 負の相関になる超モデル体系と超幸せ体系を2人作ってみる。 import pandas as pd df = pd.DataFrame({ "x" : [180,143,157,172,169,155,164,159,166,170], "y" : [43.5, 90.4, 53.2, 65.0, 62.8, 52.8 , 59.1, 55.6, 60.6, 63.5], }) df import matplotlib.pyplot as plt # 散布図 plt.scatter(df["x"],df["y"]) plt.show() 量的変数の平行座標プロットの描画(10data) import plotly.express as px fig = px.parallel_coordinates(df, dimensions=["x","y"]) fig.show() 線の交差が少ない:正の相関。これは分かる。 線の交差が多い:負の相関。交差の数というより、中心で交わってたらって感じか。 というより、量的変数だと、この時点ですでに読み取りにくい。 量的変数の平行座標プロットの描画(150data) irisをデータフレームにして、150dataに適用してみる。 # irisを格納 from sklearn.datasets import load_iris df = pd.DataFrame(iris.data, columns=iris.feature_names) df['target'] = iris.target # 平行座標プロット fig = px.parallel_coordinates(df, dimensions=['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)','target']) fig.show() やはり数が多くなれば、ここから相関について考えるのはなんかキツそうだ。目が痛い。 交差数で考えるのであれば、隣あうところとの関係しか分からない。 離れている変数同士の相関も分かるので、散布図行列やヒートマップを使った方が良さそうだ。 せめてtarget(irisの花のタイプ)毎に、どういう過程を経ているのかをみたい。 targetの0,1,2が実際は分類の変数なので、これで線を色分けするようにしてみる。 量的変数の平行座標プロットの描画を分類する dimensionsからtargetを外す。色分けに使いたいのでcolorの指定先にtargetを指定。 fig = px.parallel_coordinates(df, dimensions=['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)'] ,color="target") fig.show() 青が他の2つよりも明らかにpetallengthが短くて、petallengthだけでデータセット上では完璧な分類ができることがわかる。 これも散布図行列を見れば良いが、これはこれで新鮮で良い。 分類を数値にしておけばiris.targetで0,1,2のint型でparallel_coordinatesの中に組み込める。 分類を直接 iris.target_namesで'setosa', 'versicolor', 'virginica'にするとエラーになってしまう。 parallel_coordinatesの中にはfloatとintが組み込める模様。 dtypeでobjectは弾かれる。 質的変数の平行座標プロット てきとうな例 2値分類の質的変数2つを使う。 2×2クロス集計表で喫煙と肺癌を想定して、カイ二乗検定した時に有意(肺癌にタバコ関係ありそうだぞ)になるデータを作る。 # 質的変数(object型で格納) smoke = ["なし"]*58 + ["あり"]*290 lung = ["Yes"]*11+["No"]*47+["Yes"]*163+["No"]*127 # dfにのっける df = pd.DataFrame({ "smoke" : smoke, "lung" : lung, }) # クロス集計表 pd.crosstab(df['smoke'], df['lung']) 質的変数2つの平行座標プロットの描画 parallel_coordinatesからカテゴリ変数になったということでparallel_categoriesに変えます。 fig = px.parallel_categories(df, dimensions=["smoke","lung"]) fig.show() 質的変数の可視化という点では結構見やすい。 質的変数同士の場合散布図にしてしまうと点が重なってよく分からないが、重なりの密度を幅で教えてくれるのは助かる。 質的変数を複数にして平行座標プロットの描画 seabornのtipsというデータセットを使う。 このデータセットはfloat型2つ、int型1つ、category型4つで構成。 parallel_categoriesにデータフレームごと投げれば、 category型だけで平行座標プロットすると思ったら、 import seaborn as sns df = sns.load_dataset("tips") fig = px.parallel_categories(df) fig.show() category型だけでなく、int型も平行座標プロットされた。 intなら組み込めるということ? それならfloatをint変換すれば? # int型に変換する df["total_bill"] = df["total_bill"].astype("int") # これだけプロットされない df["tip"] = df["tip"].astype("int") # 平行座標プロット fig = px.parallel_categories(df) fig.show() 変数が1つだけ落ちた。 落ちた変数はint型にしても3~50までまばらにある感じだったので、 categoriesの中に突っ込むint型におそらく上限があるのかも。 tipsというデータセットがtipをどれだけ貰えるかみたいな話だった気がするので、tipsで色分けしてみる。 # 平行座標プロット fig = px.parallel_categories(df, dimensions = ['sex', 'smoker', 'day', 'time', 'size'],color="tip") fig.show() tips自体が10分類なので、色変えてもみにくい。 高・中・低くらいで3分類すれば見やすくなるかも。 余裕があったらまた追記します。 まとめ 質的変数の可視化では便利かも。 coordinatesはint,float。categoriesはobject,intを組み込めるようだ。 相関を感じるのは厳しくないか? dtype混在型? ここの最後に型が混在してそうな平行座標プロットがある。 df.dtypesで全てint型であるが質的変数も含んでいるかのように作られている。 作りたくなったら作ります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

psycopg2でSAVEPOINTを使って少し複雑なロールバック処理

はじめに psycopg2を使っていてネストさせたトランザクションのロールバック処理がうまく出来なかったが、対応方法を調べて思っていたことがある程度できたのでメモ。 やりたいこと トランザクションの途中で期待していた例外が発生した場合には処理を続行し(ex. INSERT時に主キー制約違反になってしまう場合だけそのINSERTをスキップ)、それ以外の例外が発生した場合には処理を終了させ全ての変更をなかったことにしたい。 ソースコードと実行結果 以下にJupyterLabでの実行結果を示す(どんな流れで実行されたのか追ってみてください)。 主キー制約違反以外の例外発生時に外側のSAVEPOINT sp1までロールバックさせています。 import time import traceback import numpy as np import pandas as pd import psycopg2 import sqlalchemy engine = sqlalchemy.create_engine(url='postgresql://postgres:postgres@192.168.56.101/mydb1') inspector = sqlalchemy.inspect(engine) columns = inspector.get_columns("company") columns # テーブル情報 [{'name': 'company', 'type': TEXT(), 'nullable': False, 'default': None, 'autoincrement': False, 'comment': None}, {'name': 'established_in', 'type': INTEGER(), 'nullable': False, 'default': None, 'autoincrement': False, 'comment': None}, {'name': 'founder', 'type': TEXT(), 'nullable': True, 'default': None, 'autoincrement': False, 'comment': None}] with engine.begin() as conn: conn.execute('DELETE FROM company;') # データを消しておく df_fail = pd.DataFrame({'company': ['A', 'B', 'C', 'A', 'D', 'E', 'F'], 'established_in': [1900, 1925, 2000, 1995, 2010, np.nan, 2000], 'founder': ['Alice', 'Bob', 'Charlie', 'David', 'Ellen', 'Fran', 'Gram']}) df_fail company established_in founder 0 A 1900.0 Alice 1 B 1925.0 Bob 2 C 2000.0 Charlie 3 A 1995.0 David 4 D 2010.0 Ellen 5 E NaN Fran 6 F 2000.0 Gram l = df_fail.values.tolist() l [['A', 1900.0, 'Alice'], ['B', 1925.0, 'Bob'], ['C', 2000.0, 'Charlie'], ['A', 1995.0, 'David'], ['D', 2010.0, 'Ellen'], ['E', nan, 'Fran'], ['F', 2000.0, 'Gram']] psyco_engine = psycopg2.connect("postgresql://postgres:postgres@192.168.56.101/mydb1") with psyco_engine as conn: with conn.cursor() as cur: cur.execute('SAVEPOINT sp1') # キーボードから中断させた場合も何も反映されない try: for inner in l: cur.execute('SAVEPOINT sp2') try: cur.execute("INSERT INTO company(company, established_in, founder) VALUES (%s, %s, %s)", (inner[0], inner[1], inner[2])) print(inner, 'INSERTED') time.sleep(3) except psycopg2.errors.UniqueViolation as e: cur.execute('ROLLBACK TO SAVEPOINT sp2') print(inner, 'UniqueViolation!!!sp2!!!') print(e) traceback.print_exc() except Exception as e: print(inner, 'UNEXPECTED-inner-!!!') print(e) traceback.print_exc() raise # 予期しない例外の場合には、sp1へ(今回の場合、nanをINSERTしようとするとエラーになるが上でキャッチされないのでsp1へ) else: cur.execute('RELEASE SAVEPOINT sp2') except Exception as e: cur.execute('ROLLBACK TO SAVEPOINT sp1') print('UNEXPECTED-outer-!!!sp1!!!') print(e) traceback.print_exc() else: cur.execute('RELEASE SAVEPOINT sp1') ['A', 1900.0, 'Alice'] INSERTED ['B', 1925.0, 'Bob'] INSERTED ['C', 2000.0, 'Charlie'] INSERTED ['A', 1995.0, 'David'] UniqueViolation!!!sp2!!! duplicate key value violates unique constraint "constraint_pkey" DETAIL: Key (company)=(A) already exists. ['D', 2010.0, 'Ellen'] INSERTED Traceback (most recent call last): File "<ipython-input-11-dc21cc04883d>", line 8, in <module> cur.execute("INSERT INTO company(company, established_in, founder) VALUES (%s, %s, %s)", (inner[0], inner[1], inner[2])) psycopg2.errors.UniqueViolation: duplicate key value violates unique constraint "constraint_pkey" DETAIL: Key (company)=(A) already exists. ['E', nan, 'Fran'] UNEXPECTED-inner-!!! integer out of range UNEXPECTED-outer-!!!sp1!!! integer out of range Traceback (most recent call last): File "<ipython-input-11-dc21cc04883d>", line 8, in <module> cur.execute("INSERT INTO company(company, established_in, founder) VALUES (%s, %s, %s)", (inner[0], inner[1], inner[2])) psycopg2.errors.NumericValueOutOfRange: integer out of range Traceback (most recent call last): File "<ipython-input-11-dc21cc04883d>", line 8, in <module> cur.execute("INSERT INTO company(company, established_in, founder) VALUES (%s, %s, %s)", (inner[0], inner[1], inner[2])) psycopg2.errors.NumericValueOutOfRange: integer out of range with engine.begin() as conn: data_on_db = pd.read_sql('SELECT * FROM company;', con=conn) data_on_db # SAVEPOINT sp1にロールバックしたので何も反映されない company established_in founder with engine.begin() as conn: conn.execute('DELETE FROM company;') おわりに SAVEPOINTを使うことで例外発生時にどの段階までロールバック処理を行わせるのかを柔軟に決められるのでうまく使いたい。 参考にしたもの
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

黙々とMNISTを見るPython(CNN)

上記のCNN版です。黙々とやります。 CNNとMLPとの違いは入力ベクトルの次元です。チャネルの概念を持つため深くなっています。他は大体同じようにコーディングできます。学習にかかる時間が大幅に長くなりますが予測精度は上がりました。 今回はランダムシードを固定しています。 import tensorflow as tf tf.__version__ '2.5.0-rc1' tf.set_random_seed = 42 準備と前処理 import numpy as np from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Activation, Dense, Dropout from tensorflow.keras.layers import Conv2D, MaxPooling2D, Flatten from tensorflow.keras.utils import to_categorical, plot_model from tensorflow.keras.datasets import mnist (x_train, y_train), (x_test, y_test) = mnist.load_data() ラベルYを2進数表記にする(one-hot vector) y_train = to_categorical(y_train) y_test = to_categorical(y_test) データXの次元を拡張する グレースケールの画像なので1チャネルあればOK。 x_train = np.reshape(x_train, [-1,28,28,1]) x_test = np.reshape(x_test, [-1,28,28,1]) データXを0から1のfloatにする (normalization) x_train = x_train.astype('float32')/255 x_test = x_test.astype('float32')/255 CNNモデルの構築 input_shape = (28,28,1) batch_size = 128 kernel_size = 3 pool_size = 2 filters = 64 dropout = 0.2 model = Sequential() model.add(Conv2D(filters=filters, kernel_size=kernel_size, activation='relu', input_shape=input_shape)) model.add(MaxPooling2D(pool_size)) model.add(Conv2D(filters=filters, kernel_size=kernel_size, activation='relu')) model.add(MaxPooling2D(pool_size)) model.add(Conv2D(filters=filters, kernel_size=kernel_size, activation='relu')) model.add(Flatten()) model.add(Dropout(dropout)) model.add(Dense(10)) model.add(Activation('softmax')) model.summary() Model: "sequential" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= conv2d (Conv2D) (None, 26, 26, 64) 640 _________________________________________________________________ max_pooling2d (MaxPooling2D) (None, 13, 13, 64) 0 _________________________________________________________________ conv2d_1 (Conv2D) (None, 11, 11, 64) 36928 _________________________________________________________________ max_pooling2d_1 (MaxPooling2 (None, 5, 5, 64) 0 _________________________________________________________________ conv2d_2 (Conv2D) (None, 3, 3, 64) 36928 _________________________________________________________________ flatten (Flatten) (None, 576) 0 _________________________________________________________________ dropout (Dropout) (None, 576) 0 _________________________________________________________________ dense (Dense) (None, 10) 5770 _________________________________________________________________ activation (Activation) (None, 10) 0 ================================================================= Total params: 80,266 Trainable params: 80,266 Non-trainable params: 0 _________________________________________________________________ plot_model(model,show_shapes=True) model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) model.fit(x_train,y_train,epochs=10,batch_size=batch_size) Epoch 1/10 469/469 [==============================] - 133s 278ms/step - loss: 0.5884 - accuracy: 0.8230 Epoch 2/10 469/469 [==============================] - 198s 422ms/step - loss: 0.0708 - accuracy: 0.9780 Epoch 3/10 469/469 [==============================] - 149s 318ms/step - loss: 0.0468 - accuracy: 0.9856 Epoch 4/10 469/469 [==============================] - 130s 277ms/step - loss: 0.0374 - accuracy: 0.9879 Epoch 5/10 469/469 [==============================] - 120s 256ms/step - loss: 0.0318 - accuracy: 0.9895 Epoch 6/10 469/469 [==============================] - 141s 300ms/step - loss: 0.0254 - accuracy: 0.9925 Epoch 7/10 469/469 [==============================] - 125s 267ms/step - loss: 0.0206 - accuracy: 0.9933 Epoch 8/10 469/469 [==============================] - 144s 307ms/step - loss: 0.0193 - accuracy: 0.9936 Epoch 9/10 469/469 [==============================] - 156s 331ms/step - loss: 0.0152 - accuracy: 0.9950 Epoch 10/10 469/469 [==============================] - 148s 315ms/step - loss: 0.0152 - accuracy: 0.9952 _,acc = model.evaluate(x_test,y_test,batch_size=batch_size,verbose=0) acc * 100 99.12999868392944 的中率99.1%の学習済みモデルが作成できた。 予測 model.predict(np.reshape(x_test[1],(1,28,28,1))).argmax() 2 y_test[1].argmax() 2 テストデータの1番目による予測値はラベルと一致しているようです。 from PIL import Image Image.fromarray((np.reshape(x_test[1],(28,28))*255).astype(np.uint8),'L') 肉眼で見ても正しく感じられます。 Confusion Matrix from sklearn import metrics metrics.confusion_matrix(y_test.argmax(axis=1), model.predict(x_test).argmax(axis=1)) array([[ 974, 0, 1, 0, 0, 1, 2, 1, 1, 0], [ 0, 1130, 1, 1, 0, 0, 0, 3, 0, 0], [ 0, 0, 1030, 0, 0, 0, 0, 1, 1, 0], [ 0, 0, 1, 1004, 0, 5, 0, 0, 0, 0], [ 0, 0, 0, 0, 967, 0, 2, 0, 4, 9], [ 0, 0, 1, 4, 0, 886, 1, 0, 0, 0], [ 2, 3, 0, 0, 2, 8, 942, 0, 1, 0], [ 0, 1, 6, 2, 0, 0, 0, 1013, 1, 5], [ 0, 0, 2, 2, 0, 0, 0, 0, 969, 1], [ 1, 0, 0, 0, 2, 4, 1, 0, 3, 998]], dtype=int64) from sympy import Matrix Matrix(metrics.confusion_matrix(y_test.argmax(axis=1), model.predict(x_test).argmax(axis=1))) $$\displaystyle \left[\begin{matrix} 974 & 0 & 1 & 0 & 0 & 1 & 2 & 1 & 1 & 0\\ 0 & 1130 & 1 & 1 & 0 & 0 & 0 & 3 & 0 & 0\\ 0 & 0 & 1030 & 0 & 0 & 0 & 0 & 1 & 1 & 0\\ 0 & 0 & 1 & 1004 & 0 & 5 & 0 & 0 & 0 & 0\\ 0 & 0 & 0 & 0 & 967 & 0 & 2 & 0 & 4 & 9\\ 0 & 0 & 1 & 4 & 0 & 886 & 1 & 0 & 0 & 0\\ 2 & 3 & 0 & 0 & 2 & 8 & 942 & 0 & 1 & 0\\ 0 & 1 & 6 & 2 & 0 & 0 & 0 & 1013 & 1 & 5\\ 0 & 0 & 2 & 2 & 0 & 0 & 0 & 0 & 969 & 1\\ 1 & 0 & 0 & 0 & 2 & 4 & 1 & 0 & 3 & 998 \end{matrix}\right]$$ 誤りの箇所をよく見る fails = [(i,(np.reshape(x_test[i],(28,28))*255).astype(np.uint8),x.argmax(),y.argmax()) for i,(x,y) in enumerate(zip(model.predict(x_test),y_test)) if x.argmax()!=y.argmax()] len(fails) 87 誤っているときの予測値とラベルの組み合わせとその出現数をまとめてみました。 dict(zip(*np.unique([str({'predict':x.argmax(),'label':y.argmax()}) for x,y in zip(model.predict(x_test),y_test) if x.argmax()!=y.argmax()],return_counts=True))) {"{'predict': 0, 'label': 6}": 2, "{'predict': 0, 'label': 9}": 1, "{'predict': 1, 'label': 6}": 3, "{'predict': 1, 'label': 7}": 1, "{'predict': 2, 'label': 0}": 1, "{'predict': 2, 'label': 1}": 1, "{'predict': 2, 'label': 3}": 1, "{'predict': 2, 'label': 5}": 1, "{'predict': 2, 'label': 7}": 6, "{'predict': 2, 'label': 8}": 2, "{'predict': 3, 'label': 1}": 1, "{'predict': 3, 'label': 5}": 4, "{'predict': 3, 'label': 7}": 2, "{'predict': 3, 'label': 8}": 2, "{'predict': 4, 'label': 6}": 2, "{'predict': 4, 'label': 9}": 2, "{'predict': 5, 'label': 0}": 1, "{'predict': 5, 'label': 3}": 5, "{'predict': 5, 'label': 6}": 8, "{'predict': 5, 'label': 9}": 4, "{'predict': 6, 'label': 0}": 2, "{'predict': 6, 'label': 4}": 2, "{'predict': 6, 'label': 5}": 1, "{'predict': 6, 'label': 9}": 1, "{'predict': 7, 'label': 0}": 1, "{'predict': 7, 'label': 1}": 3, "{'predict': 7, 'label': 2}": 1, "{'predict': 8, 'label': 0}": 1, "{'predict': 8, 'label': 2}": 1, "{'predict': 8, 'label': 4}": 4, "{'predict': 8, 'label': 6}": 1, "{'predict': 8, 'label': 7}": 1, "{'predict': 8, 'label': 9}": 3, "{'predict': 9, 'label': 4}": 9, "{'predict': 9, 'label': 7}": 5, "{'predict': 9, 'label': 8}": 1} さいごに、一体どんな画像を読み誤っていたのかを列挙します。 import matplotlib.pyplot as plt plt.figure(figsize=(4,9),dpi=200) for n,(i,img,x,y) in enumerate(fails): plt.subplot(10,9,n+1) plt.title(str(i)+':\npred:'+str(x)+'\nlabel:'+str(y),fontsize=4) plt.imshow(img,cmap='gray') plt.axis('off') plt.show() このデータセットに限って言えば、ざっくりとモデルを作るだけならMLPで充分で、時間はかかっても少しでも精度をあげようという場合にはCNNがよいです。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

LeetCodeWeekly238B: 1838. Frequency of the Most Frequent Element: 尺取り法

題意 $n$個の正の数字が与えられる。 「あなたは好きな要素を$+1$してよい」これを最大で$k$回行える。(すべて別の要素を選んでもよい) ある$x$を$y$個作りたいと思ったとき$y$の最大数はいくつか? こう考えた 例題の通り、$[1,4,8,13]$としよう。まず、ソートする。今回の場合、すでにソートされている。 $+1$しかできないので、ある数字にそろえるとすると、その数より大きい数は小さくできない。つまり、$4$は$+1$を4回行えば$8$になれるが、$8$は操作しても$1$にも$4$にもなれない。 ここで左から順に、それまでの要素をいくつ揃えられるかを考える。例えば、13に合わせるとしよう。kが十分に大きければ$[13,13,13,13]$にできる($k$が本当に大きければ$[14,14,14,14]$などにもできるが、これはyの最大数に意味がない)。 必要な$k$が小さい方から考えると、$[1,4,13,13]$, $[1,13,13,13]$, $[13,13,13,13]$のように、13の一つ左の要素から何個目まで$k$で足りるかを考えるのが良さそうである。また、この時に必要な数は、$(一番右の数 \times 要素の数) - (その区間の和)$ である。わかりやすく考えるなら、$[4,8,13]$を$[13,13,13]$にするのには、$(13-4) + (13-8) + (13-13)$が必要であるが、これは先ほどの式に他ならない。 さて、今回のrは連続区間を求めるものなので、ある要素$l$, $r$番目を選んだ時に$(r-l+1)$を最大と言い換えられる。ここで、$r$を増加させていくと、$l$は必ず減算方向にはいかない。 このため、$l=0$の状態から$r$を引き延ばしていき、各段階で、$l$をどこまで$r$に近づければならないかを考えればよい。 つまり、for rで、lを引き寄せる尺取りをする。 実装 from typing import List, Tuple from pprint import pprint class Solution: def maxFrequency(self, nums: List[int], k: int) -> int: l = 0 nums.sort() res = 0 sum = 0 for r in range(len(nums)): sum += nums[r] while True: targetnum = nums[r] * (r - l + 1) if k < (targetnum - sum): sum -= nums[l] l += 1 else: res = max(res, (r - l + 1)) break print(res) return res
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

アメフトデータ活用 huaweiスマートウォッチから位置情報を抽出する

こんにちは。 ノジマ相模原ライズというアメフトチームでアナライジングを担当しております冨上と申します。 アメフトでデータを活用する取り組みをいくつか行っているので、紹介して参ります。 今回はスマートウォッチを用いたトラッキングデータの収集に関してお伝えします。 また、先輩コーチも記事を投稿しております。どうぞご覧ください。 背景 近年ウェアラブル端末の発展により、GPSによるデータ取得が身近になってきました。 ラグビー日本代表や、サッカーのビッグクラブで活用されていることを知っている方も多いと思いますが思います。 GPSによる正確な位置情報を活用することで、練習の振り返りを行ったりパフォーマンスの分析を行い競技レベルの向上を目指せます。 しかしチームに導入するには多額の資金が必要になります。 私たちは豊富な資金があるわけではないので、出来るだけ安価に取り組めるデバイスを探しました。そこでたどり着いたのがHUAWEI Band2 Proでした。(3000円程度で入手可能) 使用機器と実行環境 データの取得までに使用した機器は以下の通りです。 HUAWEI Band2 Pro iPhone8(huawei製である必要はなし) GALLERIA Gr2060rgf-t(PC) windows10 conda 4.10.1 python3.8.5 PCはpython環境が構築されていると活用法が広がると思いますが、データ抽出のみならgoogle colabでも問題ありません。 実装 データの収集 データを活用するためには当然データを作り出す必要があります。 まずはデバイスのセットアップです。 スマホに以下のアプリをインストールし、スマートウォッチと紐付けます。 接続が完了したらセットアップは完了です。 トラッキングデータを取得したいときにはスマホ側からスタートボタンを押す必要があります。 ここまでは説明通りです。 今回はとある練習日にデータを取得してみました。 以下が実際に得られたデータです。アプリ上で簡単に確認することができます。 以外にも正確な位置情報が取れています。 しっかりとグラウンドの入り口から入って駆け回っている様子が見て取れます。 可視化後のデータだけでは面白くないので、生のデータを抽出して活用法を考えます。 HUAWEIにデータを要求する 当然HUAWEIはすべてのデータを持っていますが、私たちはそれを要求して取得することができます。 HUAWEIヘルスアプリ内の「アカウントセンター」>「プライバシーセンター」に「自分のデータを要請」という場所があります。そこで要請を行うと数日後に自分のメールに準備完了のお知らせがやってきます。 一緒に記載されているURLからデータのダウンロードを行えます。 データの解凍 ここから少しエンジニアっぽくなります。 pythonの環境構築はこちらをご覧下さい。 次にこちらのリポジトリからファイルをダウンロードします。 zip形式なので展開します。場所はどこでも構いません。 続いて7zipというツールをダウンロード、インストールします。7zipはzipファイルの解凍や圧縮に便利なツールですが、今回はstandalone console versionの7za.exeのみを使用します。 ダウンロードしたファイルの中にある7za.exeをHitravaフォルダの中にコピーします。 また、HUAWEIからダウンロードしたzipファイルを、名前をHiZip.zipと変更してHitravaフォルダにコピーします。 Hitravaフォルダはこのような構成になります。 そして最後に以下のコードを実行するとoutputフォルダが自動的に生成され、生データを取得できます。 python Hitrava.py --zip HiZip.zip --password [HUAWEI ID作成時に設定したパスワード] --json_export 精度と使い道 出てきたデータは時間ごとに位置情報を示す形式となっています。 output.tcx <?xml version="1.0" encoding="UTF-8"?><TrainingCenterDatabase xsi:schemaLocation="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2 http://www.garmin.com/xmlschemas/TrainingCenterDatabasev2.xsd" xmlns="http://www.garmin.com/xmlschemas/TrainingCenterDatabase/v2" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ns3="http://www.garmin.com/xmlschemas/ActivityExtension/v2"> <Activities> <Activity Sport="running"> <Id>2021-04-04T10:55:21+09:00</Id> <Lap StartTime="2021-04-04T10:55:21+09:00"> <TotalTimeSeconds>2394298678</TotalTimeSeconds> <DistanceMeters>465.838296</DistanceMeters> <Calories>29</Calories> <Intensity>Active</Intensity> <TriggerMethod>Manual</TriggerMethod> <Track> <Trackpoint> <Time>2021-04-04T10:55:28+09:00</Time> <HeartRateBpm xsi:type="HeartRateInBeatsPerMinute_t"> <Value>120</Value> </HeartRateBpm> </Trackpoint> <Trackpoint> <Time>2021-04-04T10:55:33+09:00</Time> <HeartRateBpm xsi:type="HeartRateInBeatsPerMinute_t"> <Value>115</Value> </HeartRateBpm> </Trackpoint> <Trackpoint> ・・・ ざっと眺めてみるとこのデバイスでは、5秒に1度しか位置を取得できていないようです。 5秒あれば40ヤード走ることも可能です。 当初は選手のスピード、加速度等様々なデータが取れると期待していましたが、このデバイスでは難しそうです。 0.2秒ごとに位置情報を取得できるデバイスもあるようなので現実活用を目指すにはそちらが必要そうです。(高価です) ウェアラブル端末でのGPS情報取得は盛り上がっている分野なので、またよい製品を見つけてトラッキングデータの取得を試みたいと思います。 追記 ノジマ相模原ライズでは一緒に活動してくれるエンジニアを募集中です! 現在以下のプロジェクトが進行中です! xリーグスタッツ自動集計システム(OCR、データの可視化) 練習映像からのパフォーマンス測定(画像認識) 試合、練習のスタッツデータベース構築 アメフト経験問わず、データを活用したい、触ってみたいという方を待っています! スタッフ申し込みはこちらのフォームからお願いします。 参考記事
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む