YouTube live カメラ動画をopencvで表示

YouTube live カメラ動画をopencvで表示

静岡県の薩埵峠のyoutubeライブ画像をopencv で表示する

当初は

YouTube動画をOpenCVでキャプチャするスクリプト
を参考に実行したがエラーとなる

YouTubeのライブ配信をOpenCVで再生する
も同様にエラーとなる

ChatGpt で
opencv でYouTubeライブカメラの画像を表示するPythonコード
を表示し実行したが
これもエラー

ERROR: Unable to extract uploader id; please report this issue on https://yt-dl.org/bug . Make sure you are using the latest version; see  https://yt-dl.org/update  on how to update. Be sure to call youtube-dl with the --verbose flag and include its complete output.
Traceback (most recent call last):
  File "/Users/snowpool/.pyenv/versions/3.10.6/lib/python3.10/site-packages/youtube_dl/YoutubeDL.py", line 815, in wrapper
    return func(self, *args, **kwargs)
  File "/Users/snowpool/.pyenv/versions/3.10.6/lib/python3.10/site-packages/youtube_dl/YoutubeDL.py", line 836, in __extract_info
    ie_result = ie.extract(url)
  File "/Users/snowpool/.pyenv/versions/3.10.6/lib/python3.10/site-packages/youtube_dl/extractor/common.py", line 534, in extract
    ie_result = self._real_extract(url)
  File "/Users/snowpool/.pyenv/versions/3.10.6/lib/python3.10/site-packages/youtube_dl/extractor/youtube.py", line 1794, in _real_extract
    'uploader_id': self._search_regex(r'/(?:channel|user)/([^/?&#]+)', owner_profile_url, 'uploader id') if owner_profile_url else None,
  File "/Users/snowpool/.pyenv/versions/3.10.6/lib/python3.10/site-packages/youtube_dl/extractor/common.py", line 1012, in _search_regex
    raise RegexNotFoundError('Unable to extract %s' % _name)
youtube_dl.utils.RegexNotFoundError: Unable to extract uploader id; please report this issue on https://yt-dl.org/bug . Make sure you are using the latest version; see  https://yt-dl.org/update  on how to update. Be sure to call youtube-dl with the --verbose flag and include its complete output.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/Users/snowpool/aw10s/youtuvelive.py", line 36, in <module>
    display_youtube_stream(youtube_url)
  File "/Users/snowpool/aw10s/youtuvelive.py", line 11, in display_youtube_stream
    info_dict = ydl.extract_info(url, download=False)
  File "/Users/snowpool/.pyenv/versions/3.10.6/lib/python3.10/site-packages/youtube_dl/YoutubeDL.py", line 808, in extract_info
    return self.__extract_info(url, ie, download, extra_info, process)
  File "/Users/snowpool/.pyenv/versions/3.10.6/lib/python3.10/site-packages/youtube_dl/YoutubeDL.py", line 824, in wrapper
    self.report_error(compat_str(e), e.format_traceback())
  File "/Users/snowpool/.pyenv/versions/3.10.6/lib/python3.10/site-packages/youtube_dl/YoutubeDL.py", line 628, in report_error
    self.trouble(error_message, tb)
  File "/Users/snowpool/.pyenv/versions/3.10.6/lib/python3.10/site-packages/youtube_dl/YoutubeDL.py", line 598, in trouble
    raise DownloadError(message, exc_info)
youtube_dl.utils.DownloadError: ERROR: Unable to extract uploader id; please report this issue on https://yt-dl.org/bug . Make sure you are using the latest version; see  https://yt-dl.org/update  on how to update. Be sure to call youtube-dl with the --verbose flag and include its complete output.

となる

youtube_dlライブラリがYouTubeのビデオからアップローダーIDを抽出することができない
で検索

Pythonのパッケージyoutube_dlで、DownloadErrorが発生する。

を参考に

pip install yt-dlp

でインストールし

import youtube_dl

の代わりに

from yt_dlp import YoutubeDL

でインポート

import cv2
import youtube_dl
from yt_dlp import YoutubeDL


def display_youtube_stream(url):
    ydl_opts = {
        'format': 'best[ext=mp4]',  # mp4 format, you can change this to other formats
        'quiet': True,
    }

    with YoutubeDL() as ydl:
        info_dict = ydl.extract_info(url, download=False)
        video_url = info_dict['url']

    cap = cv2.VideoCapture(video_url)

    if not cap.isOpened():
        print("Error: Could not open stream.")
        exit()

    while True:
        ret, frame = cap.read()
        if not ret:
            print("Failed to grab frame.")
            break

        cv2.imshow('YouTube Live Stream', frame)

        if cv2.waitKey(1) & 0xFF == ord('q'):
            break

    cap.release()
    cv2.destroyAllWindows()

# Replace with your YouTube live stream URL
youtube_url = 'https://www.youtube.com/watch?v=6S4qvf97cbQ'
display_youtube_stream(youtube_url)

として保存

これで実行すると
YouTube live画像が表示されます

なお表示しているのは
LIVE】静岡市さった峠 交通の要衝

Mac Jupyter notebook メモ

Mac Jupyter notebook メモ

Cmd + ←
で行頭へ移動後

Shift + cmd + →
で行を選択できる

単語ごとの選択は
Option + ←

単語の削除は
Option + backspace

これで
効率的にコードを書ける

[/python]
search_indicate[‘actual’] =search_indicate[‘actual’].str.replace(r”\D”, “”,regex=True)

search_indicate[‘forecast’] =search_indicate[‘forecast’].str.replace(r”\D”, “”,regex=True)

search_indicate[‘previous’] =search_indicate[‘previous’].str.replace(r”\D”, “”,regex=True)

search_indicate
[/python]

これで変換して

date2 =[]

for i in search_indicate['date']:

    new_date = datetime.datetime.strptime(i,"%d/%m/%Y").strftime("%Y-%m-%d")

    date2.append(new_date)

search_indicate['date']=search_indicate['date'].str.replace('/','-')

search_indicate['date'] = date2

search_indicate.fillna(0)

で日付を修正

あとは

actual =(

    alt.Chart(search_indicate)

    .mark_line(opacity=0.8,clip=True)

    .encode(

        x="date:T",

        y=alt.Y("actual:Q",stack=None)

    )

)



forecast =(

    alt.Chart(search_indicate)

    .mark_line(opacity=0.8,clip=True,color='red')

    .encode(

        x="date:T",

        y=alt.Y("forecast:Q",stack=None),      

    )

)



previous =(

    alt.Chart(search_indicate)

    .mark_line(opacity=0.8,clip=True,color='green')

    .encode(

        x="date:T",

        y=alt.Y("previous:Q",stack=None),      

    )

)

alt.layer(actual,forecast,previous).resolve_scale(

    y = 'independent'

)

それぞれのチャートを表示

次に
indicatorの ( 以降を
削除する

まずは

# s = 'abcxyz-xyz('



# print(my_removesuffix(s, '-xyz'))

txt ="ANZ Job Advertisements (MoM)"

print(txt)

として ( 以降を削除

Pythonで文字列の先頭と末尾から空白や文字列を削除する:strip()

を参考にしたが
strip ではできなかった

Replace と正規表現で行う

0回以上の繰り返し
*

任意の英数字は
[a-zA-Z0-9_]

\w

txt.replace("(","")

だとできた

エスケープは不要

year_economic_data2['event']=year_economic_data2['event'].replace("\([a-zA-Z0-9_]+\)","",regex=True)

year_economic_data2

とすることで解決

あとは経済指標カレンダーも同様に処理

# dealing_calender['event']= dealing_calender['event'].str.replace('(','\(').str.replace(')','\)')

dealing_calender['event']=dealing_calender['event'].replace("\([a-zA-Z0-9_]+\)","",regex=True)

とすることで解決

ただし

search_indicate['actual'] =search_indicate['actual'].str.replace(r"\D", "",regex=True)

search_indicate['forecast'] =search_indicate['forecast'].str.replace(r"\D", "",regex=True)

search_indicate['previous'] =search_indicate['previous'].str.replace(r"\D", "",regex=True)

search_indicate

だと

小数点のものまで書き換えてしまい
マイナス、小数点まで削除してしまう

不等号などはそのままにして
%
英数字のみ
削除すればいけるはず

Python: 正規表現ライブラリを使って、グループ化による置換

を参考に

import re

print(re.sub(r'([A-Z][a-z]?)(\d{1,3})', r"\\Nuc{\1}{\2}{}", "He4"))

# \Nuc{He}{4}{}

print(re.sub(r'([A-Z][a-z]?)(\d{1,3})L', r"\\Nuc{\1}{\2}{\\Lambda}", "He4L"))

# \Nuc{He}{4}{\Lambda}

みたいに

search_indicate['actual'] =search_indicate['actual'].str.replace(r"[a-zA-Z%]", "",regex=True)

search_indicate['forecast'] =search_indicate['forecast'].str.replace(r"[a-zA-Z%]", "",regex=True)

search_indicate['previous'] =search_indicate['previous'].str.replace(r"[a-zA-Z%]", "",regex=True)

search_indicate

とすればできた

とりあえず問題はあるけど
経済指標の取得後の処理はできてきた

次はIMM ポジションの取得

https://www.gaitame.com/market/imm/imm_currency.xls

からダウンロードしたいが

Mac だとそのままだとできないらしい

と思ったが Jupiter notebook からだとファイルを開けないみたい

Finder からだと普通にひらけた

Wgetは Mac にはないけど
Curl で代用できる

curl コマンド 使い方メモ

を参考に

-O オプションを付けることでファイル取得と保存ができる

!curl  "https://www.gaitame.com/market/imm/imm_currency.xls" -O

これで取得はコマンドでできるけど
Excel ファイル読み込みでエラー

No module xlrd

のエラーが出たので

【Python エラー】No module xlrd の対処法。権限がなくてxlrdモジュールをインストールできないとき

を参考に

!pip3 install xlrd

でインストール

あと excel の操作もできるように

!pip3 install openpyxl

で追加

あとは notebook を再起動すると
普通にExcelファイルの取り扱いできた

とりあえず
データ取得関連はほぼできた

Pandas 特定の文字列取得

Pandas 特定の文字列取得

lst = ["近隣10分20000円","近隣5分5000円","敷地内25000円",""]
df = pd.DataFrame(lst, columns = ['駐車場'])
import re

def fee(x):
    m = re.search(r'\d+円', x)
    if m:
        return m.group()
    else:
        return ""

df['駐車料金'] = df['駐車場'].apply(fee)
print(df)

これは apply を使うとできる

「駐車場」列から、金額のみを抽出して、新たな列「駐車料金」

として追加

これだと円が入っているので
これを金額のみにする

re.search() で正規表現で探れる

[解決!Python]re.search/re.match関数と正規表現を使って文字列から部分文字列を抽出するには
を参考に

s = 'id: deep, mail: deep@foo.com, tel: 03-0123-4567'

# re.search関数は文字列にパターンとマッチする部分があるかを調べる
m = re.search('tel: [-\d]+', s)
print(m)  # <re.Match object; span=(30, 47), match='tel: 03-0123-4567'>
r = m.group()  # re.Matchオブジェクトのgroupメソッドでマッチ全体を抽出
print(r)  # tel: 03-0123-4567

つまり

def fee(x):

    m = re.search(r'\d+円', x)

の部分で

xとして渡された文字列から

'\d+円'

で検索している

re.search(r’

で検索したら
正規表現の先頭につく`r`は何ですか?エスケープシーケンスやrow文字列を解説します
とのこと

正規表現を使う時に
R をつけることを推奨しているためらしい

次にわからんのが
m.group()

マッチした文字列を取得: group()
とあった

Pythonの正規表現マッチオブジェクトでマッチした文字列や位置を取得
を参考に

つまり

    m = re.search(r'\d+円', x)

    if m:
        return m.group()

の部分で

\d+円

にマッチする部分を格納している

次に

df['駐車料金'] = df['駐車場'].apply(fee)

の部分

pandasのapply関数の代表的な使い方
が参考になる

df = pd.DataFrame({
        "col_A": [100, 300, 200, 400, 200, 700, 200],
        "col_B": ["A", "B", "C", "D", "E", "D", "C"],
        "col_C": [2, 3, 5, 1, 2, 3, 8]
        })
df.head(10)


# 受け取ったレコードに対して、やりたい操作を記述する
def func1(row):
   return row["col_A"] * row["col_C"]



# dfをレコード単位でfunc1に渡して何らかの操作をしてもらう。戻り値は新たに作成する"col_D"に保存する。
df["col_D"] = df.apply(func1, axis=1)
df.head(10)



# 受け取った値に対して、やりたい操作を記述する
def func2(x):
    return x * 100



# dfの"col_D"の値をfunc2に渡して何らかの操作をしてもらう。戻り値は新たに作成する"col_E"に保存する。
df["col_E"] = df["col_D"].apply(func2)

df

でみるとわかるけど

Def で定義した自作メソッドを

apply() で実行している

そして新しいカラムを追加して

そこへ処理した結果を格納している

とりあえず

まずは apply などで

円の文字を削除してみよう

これができればツイートから経済指標部分を「取り出し

数値以外を削除して数値を文字列に変換すれば処理できる

Pandasで不要な文字を取り除いたり置換する方法まとめ
https://deepage.net/features/pandas-str-replace.html#%E7%89%B9%E5%AE%9A%E3%81%AE%E6%96%87%E5%AD%97%E3%82%92%E6%8C%87%E5%AE%9A%E3%81%97%E3%81%A6%E6%B6%88%E5%8E%BB

を参考に

str.strip()

で削除できる

今回は円を削除したい

df['駐車料金'].str.strip('円.')

で削除はできる

あとは反映

df['駐車料金'] =df['駐車料金'].str.strip('円.')

df

と経済指標のときみたいに代入すればok

これで文字列の編集はできるので

次に pandas で特定の文字を含む行の抽出をする

まずはツイートの取得と変数への格納

その前に経済指標カレンダーの取得

これがあっているか調べないとだめ

import pandas as pd

url = 'https://fx.minkabu.jp/indicators' #みんかぶFXの経済指標URLを取得
dfs = pd.read_html(url)[0] #テーブルのオブジェクトを生成

#本日のカレンダーを取得

dfs

でも十分に使える

余分なものをなくしてみやすくするなら

import pandas as pd


url = 'https://fx.minkabu.jp/indicators' #みんかぶFXの経済指標URLを取得
dfs = pd.read_html(url) #テーブルのオブジェクトを生成



#前処理開始
dfs1 = dfs[0].dropna(subset = [4]) #4番にNaNが入っている行はバグなので、削除
dfs2 = dfs1.drop(2,axis =1) #2番目の列を削除。axis = 1は列を削除するオプション
dfs2.columns = ["発表時間", "経済指標", "前回変動幅(USD/JPY)","前回","予想","結果"]#列名を手動で追加。



#前処理終了
dfs2    #テーブルを表示

となる

よくみたら配列で0〜6で

0が月曜

つまりdatetime などで曜日を取得してしていする必要がある

引数に曜日を数値で指定する必要ですかあるが

https://itips.krsw.biz/python-get-week-number/#st-toc-h-4

にあるように

Pythonで曜日を数字で取得する方法 まとめ

Pythonで曜日を取得するには weekday() を使う。

weekday() は今日(today)以外にもdatetime型の変数にも適用可能。

戻り値は0から6までの数値で月曜日が0に当たる。

とのこと

つまり今日の日付を取得して

これを使えば曜日指定できるはず

import datetime



# 曜日番号を取得(0は月曜日)

week_num = datetime.date.today().weekday()

print(datetime.date.today())

print(type(datetime.date.today()))

print(week_num)

このweek_num を使えば指定できるはず

これは成功

import pandas as pd

import datetime



week_num = datetime.date.today().weekday()



url = 'https://fx.minkabu.jp/indicators' #みんかぶFXの経済指標URLを取得

dfs = pd.read_html(url) #テーブルのオブジェクトを生成

print(week_num)

で曜日の数値が出る

あとは

dfs[week_num]

で本日のカレンダーを取得できる

import pandas as pd



url = 'https://fx.minkabu.jp/indicators' #みんかぶFXの経済指標URLを取得

dfs = pd.read_html(url) #テーブルのオブジェクトを生成



#前処理開始



dfs1 = dfs[0].dropna(subset = [week_num]) #4番にNaNが入っている行はバグなので、削除

dfs2 = dfs1.drop(2,axis =1) #2番目の列を削除。axis = 1は列を削除するオプション

dfs2.columns = ["発表時間", "経済指標", "前回変動幅(USD/JPY)","前回","予想","結果"]#列名を手動で追加。



#前処理終了



dfs2    #テーブルを表示

をそのあとで実行するとよりわかりやすく表示できる

そのまま経済指標のカレンダーで

Twitter で検索しても出ないが

予測値などを取得することはできるはず

次は

Pandas で時刻の比較とかトリガーとして使う方法を探す

これは

Pandas】DataFrameの文字列日付データを比較して、抽出したりする

https://www.tcom242242.net/entry/python-basic/dataframe-date-compare-extract/#toc7

を参考にまず日時の部分をdatetime へ変換する

#Dfs2 の発表時間をdatetime へ変換



def convert_date(x):

     date = datetime.datetime.strptime(x,"%Y-%m-%d %H:%M:%S")

     return date



dfs2["発表時間"] = dfs2["発表時間"].apply(convert_date)

dfs2

だとエラー
https://qiita.com/over_di/items/1270d3737e0a81719e56

Applyだとエラーになる

Pandas の to_datetime()

だとできるけど

年数の指定がないため1900年1月1日になってしまう

これを解決しないとだめ

これを解決するには

https://qiita.com/over_di/items/1270d3737e0a81719e56
Pandasのpd.to_datetimeで時刻のみ抜き出す方法

を参考に
https://qiita.com/over_di/items/1270d3737e0a81719e56
https://qiita.com/over_di/items/1270d3737e0a81719e56

.dt.time

をつければOK

dfs2["発表時間"] = pd.to_datetime(dfs2["発表時間"],format="%H:%M",errors='coerce').dt.time

dfs2

とすることで無事に変換できた

次は時刻に応じてカレンダーの列を取り出すようにする

オブジェクトを調べたら

to_datetime()

では型変換されていない

元の状態を

dfs2.dtypes
/
で調べたら


発表時間              object

経済指標              object

前回変動幅(USD/JPY)    object

前回                object

予想                object

結果                object

dtype: object

となっていた

ロイターRSS取得

ロイターRSS取得

ニュース取得にはRSSという方法もある

https://www.google.com/amp/www.algo-fx-blog.com/python-news-headlines-rss/amp/
によれば
feedparserライブラリでできるらしい

https://qiita.com/hann-solo/items/46d2bd25667618c36a5d
を参考に

ロイターRSSのURLを変更したらできたが

# ニュースのヘッドライン
print(reuters['entries'][0]['title'])

# 公開日時
print(reuters['entries'][0]['published'])
 
# URL
print(reuters['entries'][0]['link'])

でえらーになる

entries がうまく行かない

# 取得したデータを確認
reuters

で内容を確認

# 公開日時
#print(reuters['entries'][0]['published'])
print(reuters['entries'][0]['updated'])

としたら表示できた

[/python]
# ニュースの取得件数の確認
len(reuters[‘entries’])
[/python]
で確認したら現在は10が限界

# マーケットウォッチのデータを取得
market = feedparser.parse('http://feeds.marketwatch.com/marketwatch/realtimeheadlines/')
market_df = pd.DataFrame(market['entries'])
market_df.head(2)

としたが見にくい

# データを綺麗にする
market_df = market_df[['published', 'title']]
market_df.head()

で見やすくなったが title が省略される

market_df[['title']]

としても同じ

【Python】Pandasのデータフレームを省略せずに表示する方法を紹介!
を参考に省略せずに表示する

多分表示されなくてもデータの格納はされていると思う

https://qiita.com/kiddayo/items/e5ce519a234aff88af12

を参考に

pd.set_option('display.max_rows', 1500)
pd.set_option('display.max_columns', 4096)

としたが
Summary 表示は変わらない
とりあえずは保留

またRSSだと
ニュース更新頻度に問題あるため
Twitter から取得する

すでに tweepy はインストール済

あとはツイート検索と取得
これもできたので
次はテキストのみ抽出する

Streamline でエラーになったが

https://teratail.com/questions/97557
を参考に

重複したdatetime を修正し

new_date = datetime.strptime(i,"%d/%m/%Y").strftime("%Y-%m-%d")

としたら解決した

修正したので commit しようとしたら

Author identity unknown


*** Please tell me who you are.


Run


  git config --global user.email "you@example.com"

  git config --global user.name "Your Name"


to set your account's default identity.

Omit --global to set the identity only in this repository.


fatal: unable to auto-detect email address
 

となったので

git config --global user.email "メルアド"

git config --global user.name "snowpooll"
 

を実行後

git commit -m "Correction of datetime part"
 

これで

Git push origin main
 

でOK

for tweet in tweepy.Cursor(api.search_tweets, q='"#雇用統計"').items(10):

    print(tweet.text)

とすれば

#雇用統計

を含むツイートが10件取得できる

Tweet.text

でツイート情報を取得できる

Tweet.user

ツイートしたユーザ情報にアクセス

Tweet.user.name

ユーザ名の取得

次に特定ユーザのツイート

#if文にてRTとリプライを除外

[tweet.text for tweet in tweepy.Cursor(api.user_timeline, id="Qiita").items(10) if (list(tweet.text)[:2]!=['R', 'T']) & (list(tweet.text)[0]!='@')]

としたら

Unexpected parameter id

となるので id ではないかもしれない

https://toxublog.com/blog/get_tweet_tweepy/
を参考にDFにしてみた

必要なのは

ユーザ名
時刻
ツイート内容

これで一回経済指標で実験してみる

#検索条件の設定

searchkey = '#雇用統計'

item_num = 10

#検索条件を元にツイートを抽出

#tweets = tweepy.Cursor(api.search,q=searchkey,lang='ja').items(item_num)

tweets = tweepy.Cursor(api.search_tweets,q=searchkey,lang='ja').items(item_num)

tweet_data = []

for tweet in tweets:

        #tweet_dataの配列に取得したい情報を入れていく

    tweet_data.append([

        tweet.text,

        tweet.user.screen_name,

        tweet.user.name

                       ])

    #取り出したデータをpandasのDataFrameに変換

#CSVファイルに出力するときの列の名前を定義

labels=[

    'ツイート内容',

    'ユーザID',

    'アカウント名',

    ]

#tweet_dataのリストをpandasのDataFrameに変換

tweet_df = pd.DataFrame(tweet_data,columns=labels)

で大体近い感じ

あとは省略されている部分を調べる

Cvs では省略されていないので

そのままでも使えるはず

もしくはそのままでも使えるか調べる

経済指標アラートアカウント見たけど

アラートのみで実際の値はなし

Reutersとかのアカウントを使った方が正解かもしれない

とりあえず

アカウント名

ツイート内容が取得できればok

あとはここから絞り込み

python で PDF 取り扱いライブラリのインストール

python で PDF 取り扱いライブラリのインストール

ReportLab・wkhtmltopdf / pdfkit・PyPDF2・pdfminer.six・tabula-py
を使えるようにする

python でPDF作成編集、テキスト、表の抽出をすることができるようになる

reportlab のインストールは
Pythonのreportlabの使い方まとめ

を参考に

pip install reportlab

を実行

WARNING: You are using pip version 21.2.4; however, version 21.3 is available.
You should consider upgrading via the '/home/snowpool/anaconda3/bin/python -m pip install --upgrade pip' command.

という警告がでたら
pip のアップデートが必要なので

python -m pip install --upgrade pip

で pip をアップデートする

pdfkit は

HTMLをPDFに変換するライブラリ「pdfkit」をインストールする

を参考に

pip install pdfkit

でインストール

次に PyPDF2

【Python】「PyPDF2ライブラリ」によるPDFファイルの結合・分割と画像の抽出

を参考にインストール

pip だと画像の抽出に一部欠陥があるため
Github のインストーラーがおすすめらしい

https://github.com/mstamy2/PyPDF2
へアクセス

Code をクリックすると
Download ZIP がでるので
これでダウンロード

unzip PyPDF2-master.zip

で解凍して

cd PyPDF2-master/
python setup.py install

でインストール

pdfminer.six は
【Python】pdfminer.six:PDFからテキストを取得・抽出する

を参考に

pip install pdfminer.six

でインストール

【自動化】PDFの表をExcelへ(Python)

を参考に

pip install tabula-py

次に
pyinstaller

pyinstallerインストール ( Python3, Ubuntu 20.04 )

を参考に

pip3 install pyinstaller

でインストール

python でIMMポジショングラフ表示

python でIMMポジショングラフ表示

【第35回PYTHON講座】plotlyで複合グラフの作成


IMMポジションをグラフ表示するのがあったので実践

plotly を使うので

!pip install plotly

でインストール

使用するIMMポジションデータについては
外為どっとこむからダウンロード可能

https://www.gaitame.com/markets/imm/

xls ファイルをダウンロード

https://www.gaitame.com/market/imm/imm_currency.xls
がリンク先なので
wget を cron で毎週火曜日に取得するように設定すると楽かもしれない

内容は毎週火曜日に更新されている

ubuntu なので
Excel ではなく LibreOffice で代用

使用するシートは
IMMyen になる

この中で使用するセルは
日付
IMMポジション数差引
となる

まずはライブラリをインポート

import pandas as pd
import plotly

次にファイルを jupyter notebook で
immcurrency.xls
をアップロードし

xlsfile = "imm_currency.xls"

でファイルを読み込む

df_a = pd.read_excel(xlsfile, sheet_name="IMMyen", usecols=[0, 8])
df_b = pd.read_excel(xlsfile, sheet_name="IMMyen", usecols=[0, 1])

で usecols を使い抽出する列を指定
df_a には差引
df_b にはドル円レート
を格納している

0がA列になり8がI列になっている

1はB列になる

数えるときには0からなので注意

df1 = df_a[50:len(df_a)]
df2 = df_b[50:len(df_b)]

で50行目から終わりまでを指定

次に棒グラフの設定

graph1 = plotly.graph_objs.Bar(
x=df1.iloc[:, 0],
y=df1.iloc[:, 1],
yaxis="y1",
name="差引数"
)

graph_objs.Bar が棒グラフの設定になる

x=df1.iloc[:, 0],
y=df1.iloc[:, 1],

でどの列を対象にするのか視程している
0が日付
1が差引の数になる

yaxis="y1",

でy軸の名称をつけて識別できるようにする

次に折れ線グラフ

graph2 = plotly.graph_objs.Scatter(
x=df2.iloc[:, 0],
y=df2.iloc[:, 1],
yaxis="y2",
name="ドル円"
)

次に余白設定

adjust1 = (df1.iloc[:, 1].max() - df1.iloc[:, 1].min())/10 / 2
adjust2 = (df2.iloc[:, 1].max() - df2.iloc[:, 1].min())/10 / 2

adjust1、adjust2はそれぞれのY軸の最大値、最小値の差の20分の1を定義

これでグラフ表示のときにY軸上下に余白をつけることができる

次に複号グラフの位置の設定

layout = plotly.graph_objs.Layout(

    title="複合グラフ",

    xaxis=dict(title="日付"),

    yaxis=dict(
        title="IMMポジション差引数",
        range=[df1.iloc[:, 1].min() - adjust1, df1.iloc[:, 1].max() + adjust1]),

    yaxis2=dict(
        title="ドル円レート",
        range=[df2.iloc[:, 1].min() - adjust2, df2.iloc[:, 1].max() + adjust2],
        overlaying="y1", side="right", showgrid=False)

)

これは
graph_objs.Layout で設定する

range でy軸の高さ

overlaying は上に表示するときに使う

今回は

overlaying="y1"

を折れ線グラフで設定しているので
棒グラフの上に折れ線グラフがでる

side="right"

とすると
右側にy軸の値がでる

こうすることで2つのy軸表示がでる
デフォルトは左にでる

showgrid=False

を指定すると
グリッドが表示されなくなる

これがあるとグリッド線が表示されてわかりにくくなるので
今回は false にしている

あとは複号グラフの表示

data = [graph1, graph2]
fig = plotly.graph_objs.Figure(data=data, layout=layout)
fig.show()

data に表示するものを指定[/python]
graph_objs.Figure() [/python]
でデータとレイアウトをセット

show() 

で表示する

次に別の通貨で応用
ユーロドルで実践

imm_euro =  pd.read_excel(xlsfile, sheet_name="IMMeuro", usecols=[0, 8])
euro_rate = pd.read_excel(xlsfile, sheet_name="IMMeuro", usecols=[0, 1])

でユーロドルのシートからデータ取得

imm_euro_data = imm_euro[50:len(df_a)]
euro_rate_data = euro_rate[50:len(df_b)]

でデータを50行目からに絞り込む

imm_graph = plotly.graph_objs.Bar(
x=imm_euro_data.iloc[:, 0],
y=imm_euro_data.iloc[:, 1],
yaxis="y1",
name="差引数"
)
euro_graph = plotly.graph_objs.Scatter(
x=euro_rate_data.iloc[:, 0],
y=euro_rate_data.iloc[:, 1],
yaxis="y2",
name="ドル円"
)

でそれぞれのデータをグラフにセット

adjust1 = (imm_euro_data.iloc[:, 1].max() - imm_euro_data.iloc[:, 1].min())/10 / 2
adjust2 = (euro_rate_data.iloc[:, 1].max() - euro_rate_data.iloc[:, 1].min())/10 / 2

で余白を設定してグラフ表示を見やすくする

layout = plotly.graph_objs.Layout(

    title="複合グラフ",

    xaxis=dict(title="日付"),

    yaxis=dict(
        title="IMMポジション差引数",
        range=[imm_euro_data.iloc[:, 1].min() - adjust1, imm_euro_data.iloc[:, 1].max() + adjust1]),

    yaxis2=dict(
        title="ユーロ/ドルレート",
        range=[euro_rate_data.iloc[:, 1].min() - adjust2, euro_rate_data.iloc[:, 1].max() + adjust2],
        overlaying="y1", side="right", showgrid=False)

)


複号グラフの設定

data = [imm_graph, euro_graph]
fig = plotly.graph_objs.Figure(data=data, layout=layout)
fig.show()


データ表示

これでユーロドルでの
IMMポジションの比率
ユーロドルの現状がわかりやすくなる

python で今日の日付を dd/mm/YY で取得

python で今日の日付を dd/mm/YY で取得

ほとんどの場合は
yymmdd だけど
investpy で指定するときに
ddmmyy で期間を取得することになる

今日の日付を[yyyymmdd]形式の文字列で取得する。

を参考に

today =datetime.date.today().strftime('%Y%d%m')
today

とすると

‘20210409’

となる

today =datetime.date.today().strftime('%d/%m/%Y')
today

とすれば

’04/09/2021′

となる

あとは経済指標の取得期間を

economic_data = investpy.economic_calendar(time_zone=None, time_filter='time_only', countries=['japan', 'united states'], from_date='01/01/2021', to_date=today)

というように

to_date=
で指定する部分を today などの取得した変数にすればOK

ラズパイを音声でシャットダウン

ラズパイを音声でシャットダウン

車にラズパイを持ち込んで使いたいけど
シャットダウンするときに困りそうなので
音声でシャットダウンできるようにする

bluetooth ボタンも考えたけど
ハズレをひくと買い直しになるし紛失を考えると
音声でシャットダウンし
シガーソケットから給電すればエンジンをかければ電源がはいる

音声認識エンジンJulius をまずはいれる

Raspberry Pi×JuliusとPythonでスマートスピーカー風にカメラを操作

Raspberry PiとJuliusで特定の単語を認識させる

を参考に

mkdir julius
cd julius/
wget https://github.com/julius-speech/julius/archive/v4.4.2.1.tar.gz
tar xvzf v4.4.2.1.tar.gz 
cd julius-4.4.2.1/

でGit で取得し展開したファイルに移動

sudo apt-get install libasound2-dev libesd0-dev libsndfile1-dev

で必要なライブラリのインストール

Raspberry pi3B+でjuliusを動かせるようになるまでの覚書き(2019.3.10現在)

にあるように
RaspberryPi3b+の最新カーネルでは
snd-pcm-ossモジュールが含まれていないので

sudo apt-get install osspd-alsa
sudo apt-get  install libasound2-dev

でサウンドドライバをインストール

./configure --with-mictype=alsa
make
sudo make install

でコンパイルしてインストール

次に音声認識パッケージの
ディクテーションキットの取得

cd ../
mkdir julius-kit
cd julius-kit/
wget https://osdn.net/dl/julius/dictation-kit-v4.4.zip
unzip dictation-kit-v4.4.zip 

で取得

さらに必要なライブラリのインストール

sudo apt-get install alsa-utils sox libsox-fmt-all

次にマイクの設定

 arecord -l

の結果が

**** ハードウェアデバイス CAPTURE のリスト ****
カード 2: Device [USB PnP Sound Device], デバイス 0: USB Audio [USB Audio]
  サブデバイス: 1/1
  サブデバイス #0: subdevice #0

これを元に
ALSADEV設定で使用デバイスを指定

vim ~/.profile 

で設定ファイルを開き

export ALSADEV=hw:2

を最終行へ追記

hw;にはカード番号を記述

source ~/.profile 

で設定反映

あとは起動して実験

cd  ~/julius/julius-kit/dictation-kit-v4.4
julius -C main.jconf -C am-gmm.jconf -demo

起動はするけど精度が低すぎて使い物にならない

このため辞書ファイルを作成する

日本語入力ができるように mozc をインストール

sudo apt-get install fcitx-mozc

次に辞書ファイルの作成

cd ~/julius/
mkdir dict
cd dict/
sudo vim hello.yomi

でファイルを作成

おはよう おはよう
こんにちわ こんにちわ

として保存

左に認識させる言葉
右にはよみかたをひらがなで記述して
.yomi という拡張子で保存

区切りのスペースを半角にしないとバグるので注意

これを元に音素ファイルを作成する
このときに文字コードをUTF8 から EUC-JP に変換するので

iconv -f utf8 -t eucjp hello.yomi | ../julius-4.4.2.1/gramtools/yomi2voca/yomi2voca.pl | iconv -f eucjp -t utf8 > hello.phone

これでファイルが作成される
拡張子は
.phone となる

内容は

おはよう	o h a y o u
こんにちわ	k o N n i ch i w a

となる

次に構文ファイルの作成
これで
認識する文章の構成を定義している

sudo vim hello.grammar

でファイルを作成

S : NS_B HELLO NS_E
HELLO OHAYOU
HELLO KONNICHIWA

として保存

S : NS_B HELLO NS_E

NS_Bが文章の開始
NS_Eが文章の終了
という意味

HELLO OHAYOU
HELLO KONNICHIWA
の部分は
.phone ファイルの読みを大文字にしたもの

あとは語彙ファイルの作成
これはJulius に認識させたい言葉を定義するもので
拡張子は
.voca になる

sudo cp hello.phone hello.voca

でファイルをコピーし編集

% OHAYOU
おはよう o h a y o u
% KONNICHIWA
こんにちは k o N n i ch i w a
% NS_B
[s] silB
% NS_E
[/s] silE

というようにする

次に辞書ファイルへ変換

cd ~/julius/julius-4.4.2.1/gramtools/mkdfa/
mkdfa.pl ~/julius/dict/hello

を実行したがエラー

/home/pi/julius/dict/hello.grammar has 3 rules
/home/pi/julius/dict/hello.voca    has 4 categories and 4 words
---
Now parsing grammar file
Error:       parse error
Error: cannot open "/home/pi/julius/dict/hello.dfa.tmp"
---
no .dfa or .dict file generated

となる

このため
julius 辞書 自作
で検索

ラズパイ4日目①:Juliusで独自辞書を作成する

をみたところ

grammar ファイルの区切りで 
:
で区切っていないので修正

cd julius/dict/
sudo vim hello.grammar

でファイル編集

S : NS_B HELLO NS_E
HELLO : OHAYOU
HELLO : KONNICHIWA

として保存

mkdfa.pl ~/julius/dict/hello

を実行すると
.dfa
.term
.dict
ファイルが生成される

これで独自辞書ができたので
音声認識をするため

julius -C ~/julius/julius-kit/dictation-kit-v4.4/am-gmm.jconf -nostrip -gram ~/julius/dict/hello -input mic

を実行

これで辞書ファイルへ登録した
おはよう
こんにちわ
だけは認識するようになるが
それ以外は表示されない

次に辞書の追加

Raspberry Pi×JuliusとPythonでスマートスピーカー風にカメラを操作

を参考に
.yomi ファイルを編集

おはよう おはよう
こんにちわ こんにちわ
電源オフ でんげんおふ

として保存

iconv -f utf8 -t eucjp hello.yomi | ../julius-4.4.2.1/gramtools/yomi2voca/yomi2voca.pl | iconv -f eucjp -t utf8 > hello.phone

を実行

sudo vim hello.grammar

でファイルを編集

S : NS_B HELLO NS_E
HELLO : OHAYOU
HELLO : KONNICHIWA
HELLO : DENGENNOHU

として保存

sudo vim hello.voca 

でファイルを編集

% OHAYOU
おはよう o h a y o u
% KONNICHIWA
こんにちは k o N n i ch i w a
% DENGENNOHU
電源オフ d e N g e N o f u
% NS_B
[s] silB
% NS_E
[/s] silE

として保存

mkdfa.pl ~/julius/dict/hello

で辞書ファイル作成

julius -C ~/julius/julius-kit/dictation-kit-v4.4/am-gmm.jconf -nostrip -gram ~/julius/dict/hello -input mic


電源オフ
と認識されるのがわかる

次にモジュールモードでJulius の起動

julius -C ~/julius/julius-kit/dictation-kit-v4.4/am-gmm.jconf  -nostrip -gram ~/julius/dict/hello -input mic -module

これで Julius がサーバとなり
python プログラムとの通信待ちになる

次に

sudo vim speech.py

でファイルを区制

ラズパイと音声認識でLチカ

も参考に

いくつかコードも調べてみた

# -*- coding: utf-8 -*-

はpython3 なら記載不要

なおインストールしたままの状態だと

python --version

で調べると
Python 2.7.16

Python で文頭に記載する文字コードの「アレ」の名称(なんちゃら UTF-8 みたいなやつ)

を参考に

ファイルの内容は

# -*- coding: utf-8 -*-
import socket

host = 'localhost'   # Raspberry PiのIPアドレス
port = 10500         # juliusの待ち受けポート

# パソコンからTCP/IPで、自分PCのjuliusサーバに接続
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))

res = ''
while True:
 # 音声認識の区切りである「改行+.」がくるまで待つ
 while (res.find('\n.') == -1):
  # Juliusから取得した値を格納していく
  res += sock.recv(1024)

 # 音声XMLデータから、<WORD>を抽出して音声テキスト文に連結する
 word =''
 for line in res.split('\n'):
  # Juliusから取得した値から認識文字列の行を探す
  index = line.find('WORD=')

  # 認識文字列があったら...
  if index != -1:
   # 認識文字列部分だけを抜き取る
   line = line[index + 6 : line.find('"', index + 6)]
   # 文字列の開始記号以外を格納していく
   if line != '[s]':
    word = word + line

  # 「電源オフ」という文字列を認識したら...
  if word == '電源オフ':
   print("電源オフ")
  res =''

この後に

sudo python speech.py

とすると
マイクで
電源オフ
と話しかけると
電源オフ
と表示される

これで音声の認識はできたので
次に
python で linux コマンドの実行

これは subprocess モジュールを使うことでできる

Python: subprocessでOSコマンドを実行する

Pythonでシェルコマンドを実行する

Pythonからシェルコマンドを実行!subprocessでサブプロセスを実行する方法まとめ

を参考に

使い方は
subprocess.run([“実行したいコマンド”,”オプションなど”,…])
でOK

今回はshutdown コマンドを使うので

Raspberry Piの電源をブラウザからOFF

を参考に

# -*- coding: utf-8 -*-
import socket
import subprocess
cmd = "sudo shutdown -h now"

host = 'localhost'   # Raspberry PiのIPアドレス
port = 10500         # juliusの待ち受けポート

# パソコンからTCP/IPで、自分PCのjuliusサーバに接続
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((host, port))

res = ''
while True:
 # 音声認識の区切りである「改行+.」がくるまで待つ
 while (res.find('\n.') == -1):
  # Juliusから取得した値を格納していく
  res += sock.recv(1024)

 # 音声XMLデータから、<WORD>を抽出して音声テキスト文に連結する
 word =''
 for line in res.split('\n'):
  # Juliusから取得した値から認識文字列の行を探す
  index = line.find('WORD=')

  # 認識文字列があったら...
  if index != -1:
   # 認識文字列部分だけを抜き取る
   line = line[index + 6 : line.find('"', index + 6)]
   # 文字列の開始記号以外を格納していく
   if line != '[s]':
    word = word + line

  # 「電源オフ」という文字列を認識したら...
  if word == '電源オフ':
    print("電源オフ")
    subprocess.call(cmd, shell=True)
  res =''

として保存

再度

sudo python speech.py 

を実行し
マイクに電源オフと話すと
電源オフと表示された後にラズパイの電源が落ちる

python おさらい その6

python おさらい その6

標準入力+1で出力

print(int(input())+1)

次にリストの中に重複した値があるか true false で判定

list =["HND","NRT","KIX","NGO","NGO"]
flag =len(list) != len(set(list))
if flag:
    print("true")
else:
    print("False")

Pythonでリスト(配列)に重複した要素があるか判定

を参考に

set() にリストを渡すと重複する値は無視されて
位置地な値のみになるので
これを len() で比較すれば重複した要素があるか判定できる

最後の判定は true で出力なので
そのまま処理結果を出すと True になる

python の set() について調べたいなら
Pythonのsetの基本的な使い方 : set()

も参考に

リストとの違いは要素に順番を持たず
重複した値は取り除かれるということ

次にリストの中から同じ要素のカウント


array = ["HND", "NRT", "KIX", "NGO", "NGO", "NGO", "NGO", "NGO"]
count = {}

for pattern in array:
    if pattern in count:
        count[pattern] += 1
    else:
        count[pattern] = 1

for (key, value) in count.items():
    if value != 1:
        print(value)

全体の要素数をカウントするなら len() を使う
各要素ごとの出現回数をカウントするなら count() を使う

今回は

count ={}

としておくことで key value 形式で格納できるようにしている

詳しくは
PythonのCounterでリストの各要素の出現個数をカウント

を参考に

items() はキーと値のペアを両方取り出す

for (key, value) in count.items():

なら
count の中のキーと値を取り出しながらループとなる

この使い方については
Pythonで辞書をforループするkeysメソッド・valuesメソッド・itemsメソッドの使い方

を参考に

次にリストのソートと表示

list =[1, 3, 5, 6, 3, 2, 5, 23, 2]
list.sort()

for item in list:
    print(item)

昇順でリストをソートするなら
sort() で行う
なお
sort(reverse=True)
とすると降順ソートになる

リスト関連は
Pythonのリストのソートまとめ|sort(), sorted(), reverse()
を参考に

python おさらい その5

python おさらい その5

文字列の長さを表示するには len() を使う

print(len(input()))

で標準入力で入力した文字数を表示できる

次に文字列のインデックスの表示

input_line = input()
print(input_line[0])

というように 0 からインデックスが振られるので
最初の入力文字を表示するなら0を指定する

次にリストのループ表示

list =["Nara", "Shiga", "Hokkaido", "Chiba"]
for item in list:
    print(item)

今回は標準入力ではなく
リストの中身の表示

for の構文がわかっていれば
あとはリストの中身を表示するだけでOK

解説としては
【Python入門】for文を使った繰り返し文の書き方

がわかりやすいかも

次に標準入力を1文字ずつ表示
とはいっても入力自体を1文字ずつなので
別に分割するとか考えなくてOK

string=input()

for item in string:
    print(item)

最初の string の中身がリストから標準入力になっただけ

次に2つの入力値があり
最初に文字列
次に文字を入力し
文字の出現回数を計算する


string = input()
char = input()
count = 0

for item in string:
    if item == char:
        count +=1
print(count)

最初に2つの input で文字列と文字を取得

あとは回数を格納する変数を用意して
for で文字列をループしながら単語に分解

その中で文字と一致したら
カウントを増やして最後に print() で出力

次に
標準入力の
文字列の n 文字目と n + 1 文字目
という場合

count = int(input())-1
string = input()

if count +1 < len(string):
    print(string[count]+" "+string[count+1])

インデックスはゼロから数えるので
入力の時点で -1 したほうが計算が楽

文字列の長さを超えることがあるので
if で判定しておく
文字列連結は + でできる
これは java とかもおなじ
php だと . で連結なのでわかりにくいかも

s が t の中で何回出現するかカウントして出力
の場合

pattern = input()
string = input()
result = 0

for i in range(len(string) - len(pattern) + 1):
    portion = string[i:i + len(pattern)]

    if portion == pattern:
        result += 1

print(result)

次に標準入力+1で出力する場合

num= int(input())+1
print(num)

int() で整数にして+1しておけばOK

次に
n m
というように空白区切りで入力して
n 個の整数を改行区切りで標準

num = int(input())

for i in range(num):
    print(input().split()[1])

最初の num で入力回数を取得
次に for で回数分ループ
split() で分けて インデックス1の部分なら
2番めに入力したものがでるのでこれでOK

次に標準入力したものをソートして出力

input()
string = input().split()
nums=[]

for num in string:
    nums.append(int(num))
nums.sort()

for i in nums:
    print(i)

となる

格納リストを用意し
ループで入力したものを代入
代入するときに整数に変換

ループ後に sort() でソート
あとはこれをループさせて
1つずつ表示

次に入力されるn個の組を整数の値で昇順にソートして
文字列を表示

num = int(input())
inputs = {}

for i in range(num):
    tmp = input().split()
    inputs[int(tmp[1])] = tmp[0]

inputs = sorted(inputs.items())

for i in inputs:
    print(i[1])

最初に入力数を受け取る

次に 配列格納変数inputs を用意
for で range の範囲を入力値にして
tmp に格納しながら標準入力したものをループでまわす

inputs[int(tmp[1])] = tmp[0]

の部分で key value 形式で格納

inputs = sorted(inputs.items())

の部分で
sorted() で昇順にソート

sort() と sorted() の違いについては
Pythonでリストをソートするsortとsortedの違い

を参考に

基本的に文字列をソートするなら sorted() を使う

items() はすべてのキーと値の組み合わせを取得

なお値だけなら values()
キーだけならkeys() を使う

これらの辞書関連メソッドについては
辞書に含まれるすべてのキーと値を取得する

を参考に

今回は inputs に key -value 形式で格納
あとは

for i in inputs:
    print(i[1])

で 値のみループで表示すればOK