Capture The Frog

かえるぴょこぴょこw

MENU

ここ直近感動したこと

  • 竜とそばかすの姫

多分前に一回見たことあって、なんかあんまり良くないみたいな人の講評記事も見たことがある気がする。構成が云々だが、歌は良かったみたいな。でも、あんまり作品の構成とかラストとか普通に忘れてたから、ふと電車の中で見ることにした。見てる中で自分は主人公に感情移入しつつも、何よりも感動したのはあのUの世界だ。UIというか見せ方というかが素晴らしい。(素人視点だが)歌に感動しているのかUIに感動しているのかわからないくらいだった。(もちろん前者)あの、歌ってる時にできるコメントがユーザーを中心とした円上に流れているところとか。そのコメントが日本語じゃないやつは外国語→一瞬豆腐→日本語に変わっていくところとか(これがリアルタイム感あるし、最高。ユーザー体験としてはどうなのかな一瞬の外国語と豆腐いらなくねとかなるかもだけど。)そして、最高に感動したのは主人公がアンベイル(Uの仮想世界の中でアバターではなく、現実のプレイヤーの姿がそのまま表示されてしまう)された後の歌の部分で、もちろん物語的にも最高潮なんだけど、その時に主人公や他のユーザーから出る「黄色の光」だ。この光の意味とかについては何も作中で触れられていないのだけれど、あんな感じで感動した時に出る光とか。素晴らしいなと思う。何よりも美しいし、現実でもあんなふうに感動したら胸の辺りが光るとか最高だろうなって思う。多分少し前の自分だったら、新しいプロダクトの技術的なところしか見れていなくて、「ああ、はいはい綺麗だね」とか「作中だけだからね。こんなの」みたいに思っていたと思うけど、こんなふうに感動して、結構本気で現実でやってみたいなあと思えるのは、最近の自分が関わらせてもらってるプロジェクトとかの影響だろうなあ。影響受けやすいなあ自分。だけど、結構いいことだと思ってて、今までプロダクト見ても、「ああ、それってただ何とかしてるだけだよね。そんなに難しくないよねきっと」みたいな視点でしか考えられてなかったんだけど、こんな風に物の概念みたいなものを好きになれるのは、本当によかった。

  • Flip Dot

Gil Kunoさんの作品。これは美しい。やばいね。ただ見ると、「ああ、両面に色のついた小さな板が電磁石の力で回ってるのか」で終わってしまうが。そうじゃないんだよなあ。(以下、勝手な解釈)なんか自分がパソコンをというか一瞬バイナリを読んでた時というか世のプログラム書く人はわかると思うんだけれど、結局デジタルデータって「1か0」なんだな。って思うじゃん?(押し付け)でさ、昔の自分は酷いから、友達がゲームとかに課金しようかなあとか言ってる時に、そのステータスとか武器とかって所詮1か0だからなあ。そんなのに金払ってる余裕はあるのか(はい。すみません。その人が満足できるお金の使い方だったらそれでいいんです。今はわかってます。)とか言ってて、でもなんかバイナリエディタとかを開かないとそれを実感できなくて。まるで、1か0かなんて感じられないんですよ。この素晴らしく発展した世界では。でもさ、「Flip Dot」は違う。そこには1か0しかないんですよ。オンかオフか。色があるかないか。2色の色。1か0。1か0をいやがおうにも感じさせてくれる。まるで光と影。空と雲。波と砂浜。その1にも0にも入るものがあって、でもそれらって真反対なものではない。この1か0の世界で何が表せるだろう。その1と0を感じさせてくれる。その拡張性を考えさせてくれる。そもそも何がオンで何がオフなんだろう。考えさせてくれるのって大事で。波とか空とか水の波紋とかをこれで表現してらっしゃるのだけれど、それらの自然を電磁石で、プログラムで動いているのもとても良くて。このアナログから一回デジタルを挟んで、アナログに変換っていいよね。アナログって実世界に影響あるから物理的に。この変わる様子もあの音もいい。空の作品のぱちぱち変わるやつは明確に1と0を感じさせてくれるのも好きだけれど、水の波紋の作品のあの揺れている感じも好きで。

なんか、古典コンピュータと量子コンピュータを感じさせてくれる。

明確に切り替わっている方が古典コンピュータで揺れている感じの奴が量子コンピュータ。あの揺れてどっちともつかずみたいな状態が、まるで量子の重ね合わせみたいで好き。ああ、自分もフリップドットディスプレイ買ってしまおうかな。とにかく、直近のGil Kunoさんのイベント行きます。

自分の勝手な好きポイントなんだけれど、ぼんやりしたものを何らかの形にして、人にぼんやりとしたものを考えさせてくれる。芸術って最高だ。

言語化むず

edfファイルからbpm取得

polar H10で、心拍数(bpm)を取ろうかなと思ったら、.edfファイルだった

ミッション : .edfからbpmを取得せよ

pythonでやりたい。

edfファイルとは、心拍データなど生体信号に使用されるデータで、拡張子が.edfとなっている。

このデータをcsvファイルのように直接見ることは出来ないが、Pythonではいくつかのパッケージがある。

インポート

下のコードで使うもの

import pyedflib
import biosppy
import matplotlib.pyplot as plt
from statistics import mean
import pandas as pd
import japanize_matplotlib
from datetime import datetime,timedelta
from scipy.signal import resample
import matplotlib.dates as mdates

edfファイルを読み込む

使用するパッケージ : pyedflib
PyEDFlib -EDF/BDF Toolbox in Python — PyEDFlib Documentation

filename = 'edfファイルパス'
file = pyedflib.EdfReader(filename)

心拍のチャンネルを取得

edfファイルには、チャンネルと呼ばれるものがあり、異なるセンサーや電極から記録される個々の信号は各チャンネルごとに各センサーのデータがまとまっています。 edfファイルから特定の信号(今回はECG)を取得するためには、チャンネルを指定する必要がある。 ここでは、自作関数を使ってECG チャンネルを特定・抽出しています。

# ECGデータが含まれるチャンネルを特定
def find_ecg_channel(file):
    # EDFファイル内のすべてのチャンネルラベルを取得する
    channel_labels = file.getSignalLabels()
    # ECGデータが含まれるチャンネルを特定する
    for i, label in enumerate(channel_labels):
        if 'ECG' in label:
            return i
    # ECGデータが含まれるチャンネルが見つからない場合は、Noneを返す
    return None

ecg_channel = find_ecg_channel(file)

心拍と心拍数の経過時間を取得

edfのチャンネルを取得したので、チャンネルを指定してデータを読み込む。 そして、biosppyのbiosppy.signals.ecg.ecgを使って、心拍と心拍数の経過時間(秒)を取得する。

def detect_heart_rate(signal, sampling_rate):
    out = biosppy.signals.ecg.ecg(signal, sampling_rate=sampling_rate,show=False,interactive=False)
    # HeartRateの基準時間とHeartRateのデータのインデックスを返す
    return out['heart_rate_ts'],out['heart_rate']



if ecg_channel is not None:
    # チャンネルから信号とサンプリングレートを取得
    signal = file.readSignal(ecg_channel)
    sampling_rate = file.getSampleFrequency(ecg_channel)
    print('sampling rate',sampling_rate)
    
    #信号の軸とHeartRateの取得
    ts,heart_rate = detect_heart_rate(signal, sampling_rate)
    print('ts',ts)
    print('heart rate',heart_rate)
    print('bpm',len(heart_rate))

リサンプリング

心拍と心拍数の経過時間を調べることはできたが、このままでは測定機器のサンプリングレートに従っているので、まだBPM(1分あたりの心拍数)とは言えない。 なので、1分間あたりにリサンプリングする。

    # オリジナルのデータの長さとサンプリングレートを取得
    original_length = len(ts)
    original_sampling_rate = original_length / ts[-1]
    #1分あたりでサンプリングレート・1分あたりでサンプリングしたかったら、1
    sampling_rate =1/60
    # 新しいデータの長さを計算
    new_length = int(original_length * (sampling_rate / original_sampling_rate))

    # ダウンサンプリング
    downsampled_ts = resample(ts, new_length)
    downsampled_heart_rate= resample(heart_rate, new_length)

秒から日付時間へ

*心拍データが長い人用
以上でedfファイルからbpmを取り出すことができたので、matplotlibでプロットしていく。 その前に、長い時間心拍のデータをとっていたら、x軸をわかりづらい'秒'ではなく、日付時間で表したい。 そのため、x軸を秒から日付時間に変換する。そして、dataframeにすることでプロットが楽になる

   #ダウンサンプリングされた値をdatetimeの形に直す
    #測定開始の日付時間(例:2023年6月5日22時7分40秒)
    base_datetime = datetime(2023, 6, 5, 22, 7, 40)
    datetimes = []
    for i,value in enumerate(downsampled_ts):
        datetimes.append(base_datetime + timedelta(seconds=i))
    datetimes = [value.strftime('%Y-%m-%d %H:%M:%S') for value in datetimes]

    #pandasの形に直す
    heart_rate_df = pd.DataFrame(downsampled_heart_rate_h10)
    heart_rate_df = heart_rate_df.set_index(pd.to_datetime(datetimes))

matplotlibでプロット

#グラフを表示する領域を,figオブジェクトとして作成。
fig = plt.figure(figsize = (10,6), facecolor='lightblue')
ax = fig.add_subplot()
ax.plot(heart_rate_df)

#axのx軸ラベルを指定
# 開始日時と終了日時をdatetimeオブジェクトとして表現
start_datetime = datetime(2023, 6, 5, 22, 7, 40)
end_datetime = datetime(2023, 6, 5, 22, 48, 1)
# 5分ごとの日時をリストに格納
time_range_5min = []
current_time = start_datetime
while current_time <= end_datetime:
    time_range_5min.append(current_time)
#minutesを変えることで、何分ごとにx軸を表示するかを決める
    current_time += timedelta(minutes=5)
# datetimeオブジェクトを数値に変換
time_range_5min_num = [mdates.date2num(dt) for dt in time_range_5min]
# x軸の目盛りを設定
ax.set_xticks(time_range_5min_num)
# x軸のフォーマッタを設定
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S'))

#各subplotにxラベルを追加
ax.set_xlabel('time')
#各subplotにyラベルを追加
ax.set_ylabel('bpm(1m)')
ax.legend(loc = 'upper right') 
plt.show()

終結

うまくいくとこんな感じ

全体コード

import pyedflib
import biosppy
import matplotlib.pyplot as plt
from statistics import mean
import pandas as pd
import japanize_matplotlib
from datetime import datetime,timedelta
from scipy.signal import resample
import matplotlib.dates as mdates


filename = 'edfファイルパス'
file = pyedflib.EdfReader(filename)

# ECGデータが含まれるチャンネルを特定
def find_ecg_channel(file):
    # EDFファイル内のすべてのチャンネルラベルを取得する
    channel_labels = file.getSignalLabels()
    # ECGデータが含まれるチャンネルを特定する
    for i, label in enumerate(channel_labels):
        if 'ECG' in label:
            return i
    # ECGデータが含まれるチャンネルが見つからない場合は、Noneを返す
    return None

def detect_heart_rate(signal, sampling_rate):
    out = biosppy.signals.ecg.ecg(signal, sampling_rate=sampling_rate,show=False,interactive=False)
    # HeartRateの基準時間とHeartRateのデータのインデックスを返す
    return out['heart_rate_ts'],out['heart_rate']



ecg_channel = find_ecg_channel(file)

if ecg_channel is not None:
    # チャンネルから信号とサンプリングレートを取得
    signal = file.readSignal(ecg_channel)
    sampling_rate = file.getSampleFrequency(ecg_channel)
    print('sampling rate',sampling_rate)
    
    #信号の軸とHeartRateの取得
    ts,heart_rate = detect_heart_rate(signal, sampling_rate)
    print('ts',ts)
    print('heart rate',heart_rate)
    print('bpm',len(heart_rate))

    # オリジナルのデータの長さとサンプリングレートを取得
    original_length = len(ts)
    original_sampling_rate = original_length / ts[-1]
    #1分あたりでサンプリングレート
    sampling_rate =1/60
    # 新しいデータの長さを計算
    new_length = int(original_length * (sampling_rate / original_sampling_rate))

    # ダウンサンプリング
    downsampled_ts = resample(ts, new_length)
    downsampled_heart_rate= resample(heart_rate, new_length)

  #ダウンサンプリングされた値をdatetimeの形に直す
    #測定開始の日付時間(例:2023年6月5日22時7分40秒)
    base_datetime = datetime(2023, 6, 5, 22, 7, 40)
    datetimes = []
    for i,value in enumerate(downsampled_ts):
        datetimes.append(base_datetime + timedelta(minutes=i))
    datetimes = [value.strftime('%Y-%m-%d %H:%M:%S') for value in datetimes]

    #pandasの形に直す
    heart_rate_df = pd.DataFrame(downsampled_heart_rate)
    heart_rate_df = heart_rate_df.set_index(pd.to_datetime(datetimes))

else:
    print('心拍データが含まれていません')
#グラフを表示する領域を,figオブジェクトとして作成。
fig = plt.figure(figsize = (10,6), facecolor='lightblue')
ax = fig.add_subplot()
ax.plot(heart_rate_df)

#axのx軸ラベルを指定
# 開始日時と終了日時をdatetimeオブジェクトとして表現
start_datetime = datetime(2023, 6, 5, 22, 7, 40)
end_datetime = datetime(2023, 6, 5, 22, 48, 1)
# 5分ごとの日時をリストに格納
time_range_5min = []
current_time = start_datetime
while current_time <= end_datetime:
    time_range_5min.append(current_time)
#minutesを変えることで、何分ごとにx軸を表示するかを決める
    current_time += timedelta(minutes=5)
# datetimeオブジェクトを数値に変換
time_range_5min_num = [mdates.date2num(dt) for dt in time_range_5min]
# x軸の目盛りを設定
ax.set_xticks(time_range_5min_num)
# x軸のフォーマッタを設定
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S'))

#各subplotにxラベルを追加
ax.set_xlabel('time')
#各subplotにyラベルを追加
ax.set_ylabel('bpm(1m)')
plt.show()

edfファイルからbpm取得

polar H10で、心拍数(bpm)を取ろうかなと思ったら、.edfファイルだった

ミッション : .edfからbpmを取得せよ

pythonでやりたい。

edfファイルとは、心拍データなど生体信号に使用されるデータで、拡張子が.edfとなっている。

このデータをcsvファイルのように直接見ることは出来ないが、Pythonではいくつかのパッケージがある。

インポート

下のコードで使うもの

import pyedflib
import biosppy
import matplotlib.pyplot as plt
from statistics import mean
import pandas as pd
import japanize_matplotlib
from datetime import datetime,timedelta
from scipy.signal import resample
import matplotlib.dates as mdates

edfファイルを読み込む

使用するパッケージ : pyedflib
PyEDFlib -EDF/BDF Toolbox in Python — PyEDFlib Documentation

filename = 'ファイルパス'
file = pyedflib.EdfReader(filename)

心拍のチャンネルを取得

edfファイルには、チャンネルと呼ばれるものがあり、異なるセンサーや電極から記録される個々の信号は各チャンネルごとに各センサーのデータがまとまっています。 edfファイルから特定の信号(今回はECG)を取得するためには、チャンネルを指定する必要がある。 ここでは、自作関数を使ってECG チャンネルを特定・抽出しています。

# ECGデータが含まれるチャンネルを特定
def find_ecg_channel(file):
    # EDFファイル内のすべてのチャンネルラベルを取得する
    channel_labels = file.getSignalLabels()
    # ECGデータが含まれるチャンネルを特定する
    for i, label in enumerate(channel_labels):
        if 'ECG' in label:
            return i
    # ECGデータが含まれるチャンネルが見つからない場合は、Noneを返す
    return None

ecg_channel = find_ecg_channel(file)

心拍と心拍数の経過時間を取得

edfのチャンネルを取得したので、チャンネルを指定してデータを読み込む。 そして、biosppyのbiosppy.signals.ecg.ecgを使って、心拍と心拍数の経過時間(秒)を取得する。

def detect_heart_rate(signal, sampling_rate):
    out = biosppy.signals.ecg.ecg(signal, sampling_rate=sampling_rate,show=False,interactive=False)
    # HeartRateの基準時間とHeartRateのデータのインデックスを返す
    return out['heart_rate_ts'],out['heart_rate']



if ecg_channel is not None:
    # チャンネルから信号とサンプリングレートを取得
    signal = file.readSignal(ecg_channel)
    sampling_rate = file.getSampleFrequency(ecg_channel)
    print('sampling rate',sampling_rate)
    
    #信号の軸とHeartRateの取得
    ts,heart_rate = detect_heart_rate(signal, sampling_rate)
    print('ts',ts)
    print('heart rate',heart_rate)
    print('bpm',len(heart_rate))

リサンプリング

心拍と心拍数の経過時間を調べることはできたが、このままでは測定機器のサンプリングレートに従っているので、まだBPM(1分あたりの心拍数)とは言えない。 なので、1分間あたりにリサンプリングする。

    # オリジナルのデータの長さとサンプリングレートを取得
    original_length = len(ts)
    original_sampling_rate = original_length / ts[-1]
    #1分あたりでサンプリングレート・1分あたりでサンプリングしたかったら、1
    sampling_rate =1/60
    # 新しいデータの長さを計算
    new_length = int(original_length * (sampling_rate / original_sampling_rate))

    # ダウンサンプリング
    downsampled_ts = resample(ts, new_length)
    downsampled_heart_rate= resample(heart_rate, new_length)

秒から日付時間へ

*心拍データが長い人用
以上でedfファイルからbpmを取り出すことができたので、matplotlibでプロットしていく。 その前に、長い時間心拍のデータをとっていたら、x軸をわかりづらい'秒'ではなく、日付時間で表したい。 そのため、x軸を秒から日付時間に変換する。そして、dataframeにすることでプロットが楽になる

   #ダウンサンプリングされた値をdatetimeの形に直す
    #測定開始の日付時間(例:2023年6月5日22時7分40秒)
    base_datetime = datetime(2023, 6, 5, 22, 7, 40)
    datetimes = []
    for i,value in enumerate(downsampled_ts):
        datetimes.append(base_datetime + timedelta(seconds=i))
    datetimes = [value.strftime('%Y-%m-%d %H:%M:%S') for value in datetimes]

    #pandasの形に直す
    heart_rate_df = pd.DataFrame(downsampled_heart_rate_h10)
    heart_rate_df = heart_rate_df.set_index(pd.to_datetime(datetimes))

matplotlibでプロット

#グラフを表示する領域を,figオブジェクトとして作成。
fig = plt.figure(figsize = (10,6), facecolor='lightblue')
ax = fig.add_subplot()
ax.plot(heart_rate_df)

#axのx軸ラベルを指定
# 開始日時と終了日時をdatetimeオブジェクトとして表現
start_datetime = datetime(2023, 6, 5, 22, 7, 40)
end_datetime = datetime(2023, 6, 5, 22, 48, 1)
# 5分ごとの日時をリストに格納
time_range_5min = []
current_time = start_datetime
while current_time <= end_datetime:
    time_range_5min.append(current_time)
#minutesを変えることで、何分ごとにx軸を表示するかを決める
    current_time += timedelta(minutes=5)
# datetimeオブジェクトを数値に変換
time_range_5min_num = [mdates.date2num(dt) for dt in time_range_5min]
# x軸の目盛りを設定
ax.set_xticks(time_range_5min_num)
# x軸のフォーマッタを設定
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S'))

#各subplotにxラベルを追加
ax.set_xlabel('time')
#各subplotにyラベルを追加
ax.set_ylabel('bpm(1m)')
ax.legend(loc = 'upper right') 
plt.show()

全体コード

import pyedflib
import biosppy
import matplotlib.pyplot as plt
from statistics import mean
import pandas as pd
import japanize_matplotlib
from datetime import datetime,timedelta
from scipy.signal import resample
import matplotlib.dates as mdates


filename = ''
file = pyedflib.EdfReader(filename)

# ECGデータが含まれるチャンネルを特定
def find_ecg_channel(file):
    # EDFファイル内のすべてのチャンネルラベルを取得する
    channel_labels = file.getSignalLabels()
    # ECGデータが含まれるチャンネルを特定する
    for i, label in enumerate(channel_labels):
        if 'ECG' in label:
            return i
    # ECGデータが含まれるチャンネルが見つからない場合は、Noneを返す
    return None

def detect_heart_rate(signal, sampling_rate):
    out = biosppy.signals.ecg.ecg(signal, sampling_rate=sampling_rate,show=False,interactive=False)
    # HeartRateの基準時間とHeartRateのデータのインデックスを返す
    return out['heart_rate_ts'],out['heart_rate']



ecg_channel = find_ecg_channel(file)

if ecg_channel is not None:
    # チャンネルから信号とサンプリングレートを取得
    signal = file.readSignal(ecg_channel)
    sampling_rate = file.getSampleFrequency(ecg_channel)
    print('sampling rate',sampling_rate)
    
    #信号の軸とHeartRateの取得
    ts,heart_rate = detect_heart_rate(signal, sampling_rate)
    print('ts',ts)
    print('heart rate',heart_rate)
    print('bpm',len(heart_rate))

    # オリジナルのデータの長さとサンプリングレートを取得
    original_length = len(ts)
    original_sampling_rate = original_length / ts[-1]
    #1分あたりでサンプリングレート
    sampling_rate =1/60
    # 新しいデータの長さを計算
    new_length = int(original_length * (sampling_rate / original_sampling_rate))

    # ダウンサンプリング
    downsampled_ts = resample(ts, new_length)
    downsampled_heart_rate= resample(heart_rate, new_length)

  #ダウンサンプリングされた値をdatetimeの形に直す
    #測定開始の日付時間(例:2023年6月5日22時7分40秒)
    base_datetime = datetime(2023, 6, 5, 22, 7, 40)
    datetimes = []
    for i,value in enumerate(downsampled_ts):
        datetimes.append(base_datetime + timedelta(minutes=i))
    datetimes = [value.strftime('%Y-%m-%d %H:%M:%S') for value in datetimes]

    #pandasの形に直す
    heart_rate_df = pd.DataFrame(downsampled_heart_rate)
    heart_rate_df = heart_rate_df.set_index(pd.to_datetime(datetimes))

else:
    print('心拍データが含まれていません')
#グラフを表示する領域を,figオブジェクトとして作成。
fig = plt.figure(figsize = (10,6), facecolor='lightblue')
ax = fig.add_subplot()
ax.plot(heart_rate_df)

#axのx軸ラベルを指定
# 開始日時と終了日時をdatetimeオブジェクトとして表現
start_datetime = datetime(2023, 6, 5, 22, 7, 40)
end_datetime = datetime(2023, 6, 5, 22, 48, 1)
# 5分ごとの日時をリストに格納
time_range_5min = []
current_time = start_datetime
while current_time <= end_datetime:
    time_range_5min.append(current_time)
#minutesを変えることで、何分ごとにx軸を表示するかを決める
    current_time += timedelta(minutes=5)
# datetimeオブジェクトを数値に変換
time_range_5min_num = [mdates.date2num(dt) for dt in time_range_5min]
# x軸の目盛りを設定
ax.set_xticks(time_range_5min_num)
# x軸のフォーマッタを設定
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S'))

#各subplotにxラベルを追加
ax.set_xlabel('time')
#各subplotにyラベルを追加
ax.set_ylabel('bpm(1m)')
plt.show()

edfファイルからbpm取得

polar H10で、心拍数(bpm)を取ろうかなと思ったら、.edfファイルだった

ミッション : .edfからbpmを取得せよ

pythonでやりたい。

edfファイルとは、心拍データなど生体信号に使用されるデータで、拡張子が.edfとなっている。

このデータをcsvファイルのように直接見ることは出来ないが、Pythonではいくつかのパッケージがある。

インポート

下のコードで使うもの

import pyedflib
import biosppy
import matplotlib.pyplot as plt
from statistics import mean
import pandas as pd
import japanize_matplotlib
from datetime import datetime,timedelta
from scipy.signal import resample
import matplotlib.dates as mdates

edfファイルを読み込む

使用するパッケージ : pyedflib PyEDFlib -EDF/BDF Toolbox in Python — PyEDFlib Documentation

filename = 'ファイルパス'
file = pyedflib.EdfReader(filename)

心拍のチャンネルを取得

edfファイルには、チャンネルと呼ばれるものがあり、異なるセンサーや電極から記録される個々の信号は各チャンネルごとに各センサーのデータがまとまっています。 edfファイルから特定の信号(今回はECG)を取得するためには、チャンネルを指定する必要がある。 ここでは、自作関数を使ってECG チャンネルを特定・抽出しています。

# ECGデータが含まれるチャンネルを特定
def find_ecg_channel(file):
    # EDFファイル内のすべてのチャンネルラベルを取得する
    channel_labels = file.getSignalLabels()
    # ECGデータが含まれるチャンネルを特定する
    for i, label in enumerate(channel_labels):
        if 'ECG' in label:
            return i
    # ECGデータが含まれるチャンネルが見つからない場合は、Noneを返す
    return None

ecg_channel = find_ecg_channel(file)

心拍と心拍数の経過時間を取得

edfのチャンネルを取得したので、チャンネルを指定してデータを読み込む。 そして、biosppyのbiosppy.signals.ecg.ecgを使って、心拍と心拍数の経過時間(秒)を取得する。

def detect_heart_rate(signal, sampling_rate):
    out = biosppy.signals.ecg.ecg(signal, sampling_rate=sampling_rate,show=False,interactive=False)
    # HeartRateの基準時間とHeartRateのデータのインデックスを返す
    return out['heart_rate_ts'],out['heart_rate']



if ecg_channel is not None:
    # チャンネルから信号とサンプリングレートを取得
    signal = file.readSignal(ecg_channel)
    sampling_rate = file.getSampleFrequency(ecg_channel)
    print('sampling rate',sampling_rate)
    
    #信号の軸とHeartRateの取得
    ts,heart_rate = detect_heart_rate(signal, sampling_rate)
    print('ts',ts)
    print('heart rate',heart_rate)
    print('bpm',len(heart_rate))

リサンプリング

心拍と心拍数の経過時間を調べることはできたが、このままでは測定機器のサンプリングレートに従っているので、まだBPM(1分あたりの心拍数)とは言えない。 なので、1分間あたりにリサンプリングする。

    # オリジナルのデータの長さとサンプリングレートを取得
    original_length = len(ts)
    original_sampling_rate = original_length / ts[-1]
    #1分あたりでサンプリングレート・1分あたりでサンプリングしたかったら、1
    sampling_rate =1/60
    # 新しいデータの長さを計算
    new_length = int(original_length * (sampling_rate / original_sampling_rate))

    # ダウンサンプリング
    downsampled_ts = resample(ts, new_length)
    downsampled_heart_rate= resample(heart_rate, new_length)

秒から日付時間へ

*心拍データが長い人用 以上でedfファイルからbpmを取り出すことができたので、matplotlibでプロットしていく。 その前に、長い時間心拍のデータをとっていたら、x軸をわかりづらい'秒'ではなく、日付時間で表したい。 そのため、x軸を秒から日付時間に変換する。そして、dataframeにすることでプロットが楽になる

   #ダウンサンプリングされた値をdatetimeの形に直す
    #測定開始の日付時間(例:2023年6月5日22時7分40秒)
    base_datetime = datetime(2023, 6, 5, 22, 7, 40)
    datetimes = []
    for i,value in enumerate(downsampled_ts):
        datetimes.append(base_datetime + timedelta(seconds=i))
    datetimes = [value.strftime('%Y-%m-%d %H:%M:%S') for value in datetimes]

    #pandasの形に直す
    heart_rate_df = pd.DataFrame(downsampled_heart_rate_h10)
    heart_rate_df = heart_rate_df.set_index(pd.to_datetime(datetimes))

matplotlibでプロット

#グラフを表示する領域を,figオブジェクトとして作成。
fig = plt.figure(figsize = (10,6), facecolor='lightblue')
ax = fig.add_subplot()
ax.plot(heart_rate_df)

#axのx軸ラベルを指定
# 開始日時と終了日時をdatetimeオブジェクトとして表現
start_datetime = datetime(2023, 6, 5, 22, 7, 40)
end_datetime = datetime(2023, 6, 5, 22, 48, 1)
# 5分ごとの日時をリストに格納
time_range_5min = []
current_time = start_datetime
while current_time <= end_datetime:
    time_range_5min.append(current_time)
#minutesを変えることで、何分ごとにx軸を表示するかを決める
    current_time += timedelta(minutes=5)
# datetimeオブジェクトを数値に変換
time_range_5min_num = [mdates.date2num(dt) for dt in time_range_5min]
# x軸の目盛りを設定
ax.set_xticks(time_range_5min_num)
# x軸のフォーマッタを設定
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S'))

#各subplotにxラベルを追加
ax.set_xlabel('time')
#各subplotにyラベルを追加
ax.set_ylabel('bpm(1m)')
ax.legend(loc = 'upper right') 
plt.show()

全体コード

import pyedflib
import biosppy
import matplotlib.pyplot as plt
from statistics import mean
import pandas as pd
import japanize_matplotlib
from datetime import datetime,timedelta
from scipy.signal import resample
import matplotlib.dates as mdates


filename = ''
file = pyedflib.EdfReader(filename)

# ECGデータが含まれるチャンネルを特定
def find_ecg_channel(file):
    # EDFファイル内のすべてのチャンネルラベルを取得する
    channel_labels = file.getSignalLabels()
    # ECGデータが含まれるチャンネルを特定する
    for i, label in enumerate(channel_labels):
        if 'ECG' in label:
            return i
    # ECGデータが含まれるチャンネルが見つからない場合は、Noneを返す
    return None

def detect_heart_rate(signal, sampling_rate):
    out = biosppy.signals.ecg.ecg(signal, sampling_rate=sampling_rate,show=False,interactive=False)
    # HeartRateの基準時間とHeartRateのデータのインデックスを返す
    return out['heart_rate_ts'],out['heart_rate']



ecg_channel = find_ecg_channel(file)

if ecg_channel is not None:
    # チャンネルから信号とサンプリングレートを取得
    signal = file.readSignal(ecg_channel)
    sampling_rate = file.getSampleFrequency(ecg_channel)
    print('sampling rate',sampling_rate)
    
    #信号の軸とHeartRateの取得
    ts,heart_rate = detect_heart_rate(signal, sampling_rate)
    print('ts',ts)
    print('heart rate',heart_rate)
    print('bpm',len(heart_rate))

    # オリジナルのデータの長さとサンプリングレートを取得
    original_length = len(ts)
    original_sampling_rate = original_length / ts[-1]
    #1分あたりでサンプリングレート
    sampling_rate =1/60
    # 新しいデータの長さを計算
    new_length = int(original_length * (sampling_rate / original_sampling_rate))

    # ダウンサンプリング
    downsampled_ts = resample(ts, new_length)
    downsampled_heart_rate= resample(heart_rate, new_length)

  #ダウンサンプリングされた値をdatetimeの形に直す
    #測定開始の日付時間(例:2023年6月5日22時7分40秒)
    base_datetime = datetime(2023, 6, 5, 22, 7, 40)
    datetimes = []
    for i,value in enumerate(downsampled_ts):
        datetimes.append(base_datetime + timedelta(minutes=i))
    datetimes = [value.strftime('%Y-%m-%d %H:%M:%S') for value in datetimes]

    #pandasの形に直す
    heart_rate_df = pd.DataFrame(downsampled_heart_rate)
    heart_rate_df = heart_rate_df.set_index(pd.to_datetime(datetimes))

else:
    print('心拍データが含まれていません')
#グラフを表示する領域を,figオブジェクトとして作成。
fig = plt.figure(figsize = (10,6), facecolor='lightblue')
ax = fig.add_subplot()
ax.plot(heart_rate_df)

#axのx軸ラベルを指定
# 開始日時と終了日時をdatetimeオブジェクトとして表現
start_datetime = datetime(2023, 6, 5, 22, 7, 40)
end_datetime = datetime(2023, 6, 5, 22, 48, 1)
# 5分ごとの日時をリストに格納
time_range_5min = []
current_time = start_datetime
while current_time <= end_datetime:
    time_range_5min.append(current_time)
#minutesを変えることで、何分ごとにx軸を表示するかを決める
    current_time += timedelta(minutes=5)
# datetimeオブジェクトを数値に変換
time_range_5min_num = [mdates.date2num(dt) for dt in time_range_5min]
# x軸の目盛りを設定
ax.set_xticks(time_range_5min_num)
# x軸のフォーマッタを設定
ax.xaxis.set_major_formatter(mdates.DateFormatter('%H:%M:%S'))

#各subplotにxラベルを追加
ax.set_xlabel('time')
#各subplotにyラベルを追加
ax.set_ylabel('bpm(1m)')
plt.show()

streamlit cloud上でAuth0を使用したログインを行う際のAuth0の設定

streamlit上でAuth0を使用したログインを行ったときに、ローカルでのログインは出来るが、streamlit cloudでデプロイしたときには動かないことがあります。
ローカル時と同じ設定方法ではAuth0は動きません。

しかし、多くの場合、解説記事ではローカルでの設定しか書かれておらず、デプロイする際の設定は書かれていません。
多くの人がここで戸惑っています。

https://discuss.streamlit.io/t/new-component-auth0-component-a-simple-way-to-authenticate-a-user/18260/11


そこで、ここではstreamlitを使用して開発した自分のアプリをstreamlit cloudでデプロイしたときのAuth0の設定について書いていきます。


streamlit上でAuth0でログインする基本のコンポーネントとして、streamlit-auth0を使用させて頂きます。
Auth0以外の基本的な設定は、レポジトリ内のReadme.mdに沿って行ってください。
github.com

Thanks, conradbez!!!

紹介記事
discuss.streamlit.io






方法

1,callback URL

https://YOUR_APP_ON_STREAMLIT_CLOUD_DOMAIN/~/+/component/auth0_component.login_button/index.html, http://YOUR_AUTH0_DOMAIN/component/auth0_component.login_button/index.html

2,Allowed Web origin

https://YOUR_APP_ON_STREAMLIT_CLOUD_DOMAIN/~/+/component/auth0_component.login_button/index.html




↓存在しないアカウントとstreamlit cloud上のアプリ
Auth0 settings page
My App url on streamlit cloud

https://crum7-test-streamlit-appmikata-main-ub2ry5.streamlit.app/


Auth0の設定
1,call back URL

https://crum7-test-streamlit-appmikata-main-ub2ry5.streamlit.app/~/+/component/auth0_component.login_button/index.html, http://dev-o3y3v7wthueiyyyt.us.auth0.com/component/auth0_component.login_button/index.html


2,Allowed Web origin

https://crum7-test-streamlit-appmikata-main-ub2ry5.streamlit.app/~/+/component/auth0_component.login_button/index.html

streamlit cloud上でAuth0を使用したログインを行う際のAuth0の設定

streamlit上でAuth0を使用したログインを行ったときに、ローカルでのログインは出来るが、streamlit cloudでデプロイしたときには動かないことがあります。
ローカル時と同じ設定方法ではAuth0は動きません。

しかし、多くの場合、解説記事ではローカルでの設定しか書かれておらず、デプロイする際の設定は書かれていません。
多くの人がここで戸惑っています。

https://discuss.streamlit.io/t/new-component-auth0-component-a-simple-way-to-authenticate-a-user/18260/11


そこで、ここではstreamlitを使用して開発した自分のアプリをstreamlit cloudでデプロイしたときのAuth0の設定について書いていきます。


streamlit上でAuth0でログインする基本のコンポーネントとして、streamlit-auth0を使用させて頂きます。
Auth0以外の基本的な設定は、レポジトリ内のReadme.mdに沿って行ってください。
github.com

Thanks, conradbez!!!

紹介記事
discuss.streamlit.io






方法

1,callback URL

https://YOUR_APP_ON_STREAMLIT_CLOUD_DOMAIN/~/+/component/auth0_component.login_button/index.html, http://YOUR_AUTH0_DOMAIN/component/auth0_component.login_button/index.html

2,Allowed Web origin

https://YOUR_APP_ON_STREAMLIT_CLOUD_DOMAIN/~/+/component/auth0_component.login_button/index.html




↓存在しないアカウントとstreamlit cloud上のアプリ
Auth0 settings page
My App url on streamlit cloud

https://crum7-test-streamlit-appmikata-main-ub2ry5.streamlit.app/


Auth0の設定
1,call back URL

https://crum7-test-streamlit-appmikata-main-ub2ry5.streamlit.app/~/+/component/auth0_component.login_button/index.html, http://dev-o3y3v7wthueiyyyt.us.auth0.com/component/auth0_component.login_button/index.html


2,Allowed Web origin

https://crum7-test-streamlit-appmikata-main-ub2ry5.streamlit.app/~/+/component/auth0_component.login_button/index.html

機械学習 よく使う関数

Pandas

import pandas as pd

df,dataframe

axisとは。。

列(縦)に沿った処理はaxis=0
行(横)に沿った処理はaxis=1

DataFrameとSeriesの違い。。

Seriesは1つのカラムを指すデータ構造。1次元構造

DataFrameは多数のSeriesの集まり。2次元構造


・pd.read_csv()

csvをdataframeとして読み込む

index_col:indexとするcolumn名

names=['colomnの名前','colomnの名前']

 

・df.to_csv('csv_name')

DataFrameをcsvに書き出し


・df.colums

dataframe内の列名のみを表示

 

・df.dropna(axis=1)

NaNを削除

 

・df.カラム名

DataFrame内の特定の列を指定する

 

・まとめて特定の列を一つの変数に入れる

colums=["example1","example2","example3"]

df[colums]

列名をリストにまとめて、dataframe[リスト]とすることで複数の特定の列を一気に読み出せる

 

・iloc[0]

指定した数字の行数を受け取れる

df.列の名前.iloc[0] 指定した列の0行目の値を取得

.iloc[0:10] 10行目まで取得

 .iloc[ [ 0,1,10] , : ] 指定した複数の行(0,1,10)&すべての列を取得

 

・.loc

.loc[ [ 0,10,100 ] , [ 'country' , 'province' , 'region_1' ] ]  指定した複数の行&指定した複数の列を取得

同じことを.ilocでやろうとしても無理

.loc [ df.country == ' Italy ' ] df.countryがItalyの行を取得

df.loc[(df.country.isin(['Australia','New Zealand'])) & (df.points >= 95)] .locのなかで、.isin(List)を使用すると、listに合致するものを取得

 

・df.describe()

count,mean, std,min,25%,50%,75%,maxを一括で表示

 

・df.median()

最頻値を取得

 

・df.unique()

列の情報を重複なしで取得

 

・df.value_counts()

それぞれの要素がいくつあるのかを取得

 

・df.mean()

平均値を取得

センタリングといって、各特徴量の中心を0に揃える。各特徴量において、平均を計算し、それを各値から引く前処理で使用される。↓

df.price - df.price.mean()

 

・df.groupby()

グループに分ける

 

・df.groupby().agg([len, min, max])

もう一つのgroupby()メソッドとして、agg()がある。

len,min,maxを出してくれる

 

・df.dtype

なんのtypeなのかを調査

 

・df.astype('type名')

dataframeを好きなtypeに変換する

 

・pd.concat([df,df])

複数のDataFrameを結合

 

 

 

 

 

sklearn

・DecisionTreeRegressor(random_state=1)

モデルを定義する。random_state に数値を指定し、毎回同じ結果になるようにする。

 

・fit()

モデルの学習

 

・predict()

モデルの推論

 

・train_test_split()

例:train_X, val_X, train_y, val_y = train_test_split(X, y, random_state=1)

データを訓練用とテスト用に分ける

割合、個数を指定: 引数test_size, train_size
シャッフルするかを指定: 引数shuffle
乱数シードを指定: 引数random_state

 

・mean_absolute_error(検証用データ,推論結果)

平均絶対誤差の計算

 

 

tensorflow keras

KerasのLiner層(全結合層)

model = keras.Sequential([

 #最初だからinput_sizeが必要

    layers.Dense(unitサイズ , input_shape=[入力サイズ])

 

 #途中

 layers.Dense(unitサイズ)

 

 #最後の全結合層

  layers.Dense(1)

 

])

 

重みをみる

w, b = model.weights

 

KerasのActivation層(活性化関数層)

model = keras.Sequential([
    layers.Activation('relu'),
    layers.Dense(32),
    layers.Activation('relu'),
    layers.Dense(1),
])

 

Kerasのロス関数・最適化関数

model.compile(
    optimizer = "adam",
    loss="mae"
)

optimizerで最適化アルゴリズムを記述

lossでロス関数を記述

 

optimizerの種類:adam,sgd

lossの種類:mae,binary_crossentropy,

metricsの種類:['binary_accuracy'],

 

 

 

 

model train

train_X, val_X, train_y, val_y = train_test_split(X, y, random_state=1)
history = model.fit(
    train_X,train_y,
    validation_data=(val_X,val_y),
    batch_size=256,
    epochs = 200
)

 

・trainの様子をgifで表示

 

learning_rate = 0.05
batch_size = 32
num_examples = 256

animate_sgd(
    learning_rate=learning_rate,
    batch_size=batch_size,
    num_examples=num_examples,
    # You can also change these, if you like
    steps=50, # total training steps (batches seen)
    true_w=3.0, # the slope of the data
    true_b=2.0, # the bias of the data
)

 

・早期終了

early_stopping = EarlyStopping(
    min_delta=0.001,
    patience=5,
    restore_best_weights=True,
)

 

ドロップアウト

model = keras.Sequential([
    layers.Dense(128, activation='relu', input_shape=input_shape),
    layers.Dropout(rate=0.3),
    layers.Dense(64, activation='relu'),
    layers.Dropout(rate=0.3),
    layers.Dense(1)
])

全結合層と全結合層の間にDropout()を挟む

 

・BatchNormalization

model = keras.Sequential([
    layers.BatchNormalization(),
    layers.Dense(512, activation='relu', input_shape=input_shape),
    layers.BatchNormalization(),
    layers.Dense(512, activation='relu'),
    layers.BatchNormalization(),
    layers.Dense(512, activation='relu'),
    layers.BatchNormalization(),
    layers.Dense(1),
])

Dropoutと同じく、各層の間に入れる