[Python] 299 自製ライブラリによるpandasの機能拡張

pandasで欲しい機能については自製ライブラリで機能拡張することにしました。

これをうまく利用すれば、自分の好きなように書いてcsvファイルを作ったりできそうです。

個人開発だからできることで、共同開発でこんなことしたらヒンシュクものですね。

import pandas as pd

# データフレームの列に欠損値があっても他の値を数値型変換する関数
def to_numeric_column(df,column_name):
    df[column_name] = df[column_name].fillna(0)
    df[column_name] = pd.to_numeric(df[column_name],downcast='signed')
    df[column_name] = df[column_name].replace(0,'')
    return df
from my_library import pandas_ex as pd_ex

df = pd_ex.to_numeric_column(df,'人気')

# 以前のコード
# df['人気'] = df['人気'].fillna(0)
# df['人気'] = pd.to_numeric(df['人気'],downcast='signed')
# df['人気'] = df['人気'].replace(0,'')

[Python] 298 pandasのto_numeric関数における欠損値の扱い

pandasのto_numeric関数において空白がある場合はNaNに変換されて、他のデータは指定の数値型に変換されません。

このようなことはこれまで起こらなかったのですが、競争除外馬が出たおかげでコードの不備が発覚しました。

対策として欠損値を0で埋めてからto_numeric関数を使い、あとで0を空白にreplaceしました。指定の範囲で0を使わない場合に有効です。

空白やNaNを含む列の数値型変換ができないのは惜しいところです。

df['人気'] = df['人気'].fillna(0)
df['人気'] = pd.to_numeric(df['人気'],downcast='signed')

df['人気'] = df['人気'].replace(0,'')

[C言語] 08 アセンブラファイルの修正

C言語のアセンブラファイルをチェックしたところ、関数ファイル内の使わない関数を読み込んでいたので削除しましたが、処理時間は変わらずでした。

処理時間の測定にはPythonを使いました。

まあ端折っても最初の読み込みがなくなるだけなのでそんなところでしょう。ループ箇所などをチェックする方がいいようです。

import datetime,time,os,subprocess

start = time.time()

dt_now = datetime.datetime.now()

print('スタート 現在時刻 ' + str(dt_now))

proc = subprocess.run("as -o ./test.o ./test.s; gcc -o ./test ./test.o ; ./test; ECHO 'C言語実行完了'", shell=True, stdout= subprocess.PIPE, stderr = subprocess.PIPE)

process_time = time.time() - start
td = datetime.timedelta(seconds = process_time)
dt_now2 = datetime.datetime.now()

print('テスト 完了 ' + str(td) + ' 現在時刻 ' + str(dt_now2))

# Macのデスクトップ通知
os.system("osascript -e 'display notification \"テスト完了\n\"'")

[Java] 84 Swing 22 JEditorPaneハイパーリンク・クリック後のHTMLファイル作成 複数table各列の設定

前回の続きです。HTMLのレイアウトを一応完成させました。

列ごとの設定には少し手間取りました。複数tableの設定に関するネット情報は調べた範囲では見当たりませんでした。まあ情報が乏しくても推測で分かると思います。

body {
    background-color: #f0f8ff;
}
th {
    text-align: center;
    }
.container {
    display: block;
}
#tableA{
    background-color: #ffffe0;
    margin: 15px 5px 15px 5px;
}
#tableB{
    background-color: #e0ffff;
    margin: 15px 5px 15px 5px;
}
#tableC{
    background-color: #7fffd4;
    margin: 15px 5px 15px 5px;
}
#tableB tr td:nth-of-type(1){text-align: right} /* 着順 */
#tableB tr td:nth-of-type(2){text-align: right} /* 枠番 */
#tableB tr td:nth-of-type(3){text-align: right} /* 馬番 */
#tableB tr td:nth-of-type(4){width: 160px;padding:0 0 0 5px} /* 馬名 */
#tableB tr td:nth-of-type(5){text-align: center} /* 性齢 */
#tableB tr td:nth-of-type(6){text-align: right;width: 45px} /* 斤量 */
#tableB tr td:nth-of-type(7){width: 80px;padding:0 0 0 5px} /* 騎手 */
#tableB tr td:nth-of-type(8){width: 60px} /* タイム */
#tableB tr td:nth-of-type(9){text-align: left} /* 着差 */
#tableB tr td:nth-of-type(10){text-align: left} /* 通過 */
#tableB tr td:nth-of-type(11){text-align: right;width: 45px;} /* 上り */
#tableB tr td:nth-of-type(12){text-align: right; width: 45px} /* 単勝 */
#tableB tr td:nth-of-type(13){text-align: right} /* 人気 */
#tableB tr td:nth-of-type(14){width: 85px;padding:0 0 0 5px} /* 馬体重 */
#tableB tr td:nth-of-type(15){width: 100px} /* 調教師 */
#tableB tr td:nth-of-type(16){padding:0 0 0 5px} /* 馬主 */
#tableB tr td:nth-of-type(17){text-align: right} /* 賞金 */

[Java] 83 Swing 21 JEditorPaneハイパーリンク・クリック後のHTMLファイル作成 各tableの設定

HTMLの各tableにidを付けて色設定等を変えてみました。

同じ文字列(class=”dataframe”)をそれぞれ違う文字列(id=”tableA”他)に変えるには、このような野暮ったい方法しか思いつきませんでした。

pandasではtableの線が2重線なので1重線にして色を付けました。

<CSVファイルの読み込み以降>

try:
    df2 = pd.read_csv(racefile_path,encoding="shift_JIS")
except UnicodeDecodeError:
    df2 = pd.read_csv(racefile_path,encoding="UTF-8")

# df2を3つのtableに分割
dfA = df2[['1 日付','2 開催','3 レース','4 レース名','5 条件','6 コース','7 天候','8 馬場状態','9 発走時刻']]
dfB = df2[['着順','枠番','馬番','馬名','性齢','斤量','騎手','タイム','着差','通過','上り','単勝','人気','馬体重','調教師','馬主','賞金(万円)']]

dfB2 = dfB[:-3]
dfC = dfB[-2:]
print(dfC)

dfC2 = dfC[['着順','枠番']]
print(dfC2)

# dfAのデータ行のみ抽出
row_num = len(df2)-3
print(row_num)

# データ行以外の行番号をリスト化
row_list = [row for row in range(0,row_num + 3) if not row==row_num]
print(row_list)

dfA2 = dfA.drop(dfA.index[row_list])
dfA3 = dfA2.rename(columns={'1 日付': '日付','2 開催': '開催','3 レース': 'レース','4 レース名': 'レース名','5 条件': '条件','6 コース': 'コース','7 天候': '天候','8 馬場状態': '馬場状態','9 発走時刻': '発走時刻'})

dfB3 = dfB2.fillna('')
print(dfB3.dtypes)

try:
    dfB3['着順'] = pd.to_numeric(dfB3['着順'], downcast='signed')
except Exception as e:
    print(e)

dfB3['枠番'] = pd.to_numeric(dfB3['枠番'], downcast='signed')
dfB3['馬番'] = pd.to_numeric(dfB3['馬番'], downcast='signed')
dfB3['人気'] = pd.to_numeric(dfB3['人気'], downcast='signed')
print(dfB3.dtypes)

html_string = '''
<html>
    <head>
        <meta charset="UTF-8">
        <title>{raceID}</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <div class="container">
            {tableA}
            {tableB}
            {tableC}
        </div>
    </body>
</html>
'''

with open(html_file,'w') as f:
    f.write(html_string.format(tableA=dfA3.to_html(index=False),tableB=dfB3.to_html(index=False),tableC=dfC2.to_html(index=False,header=False),raceID=raceID))

with open(html_file,'r') as f:
    html = f.read()

htmlH = html.split('<table border="1" class="dataframe">')[0]
htmlA = html.split('<table border="1" class="dataframe">')[1]
htmlB = html.split('<table border="1" class="dataframe">')[2]
htmlC = html.split('<table border="1" class="dataframe">')[3]

htmlA2 = '<table id="tableA" border="1" style="border-collapse: collapse; border-color: #add8e6">' + htmlA
htmlB2 = '<table id="tableB" border="1" style="border-collapse: collapse; border-color: #ffb6c1">' + htmlB
htmlC2 = '<table id="tableC" border="1" style="border-collapse: collapse; border-color: #f0e68c">' + htmlC

html_new = htmlH + htmlA2 + htmlB2 + htmlC2

with open(html_file,'w') as f:
    f.write(html_new)
body {
    background-color: #f0f8ff;
}
th {
    text-align: center;
    }
.container {
    display: block;
}
#tableA{
    background-color: #ffffe0;
    margin: 15px 5px 15px 5px;
}
#tableB{
    background-color: #e0ffff;
    margin: 15px 5px 15px 5px;
}
#tableC{
    background-color: #7fffd4;
    margin: 15px 5px 15px 5px;
}

[Java] 82 Swing 20 JEditorPaneハイパーリンク・クリック後のHTMLファイル作成 table列のデータ型変更

もう一息のところまで出来ました。

データ型の変更でastype関数が効かないため、to_numeric関数を使いました。to_numeric関数の取り扱いはドキュメントを読まないと分かりませんでした。中級者向けでしょうか。

あとは2番目のtableのいくつかの列を右寄せにして一応完成になります。

各tableにIDを付けて2番目だけ書式設定する必要がありますが、少し工数が掛かりそうなので次回以降の記事で紹介します。

このアプリを作り上げてきて、ようやく実用に耐えるレベルに達したように思います。インターネット接続が従量制だった頃であれば、どれだけコストが浮いたことでしょう。

<CSVファイルの読み込み以降>

try:
    df2 = pd.read_csv(racefile_path,encoding="shift_JIS")
except UnicodeDecodeError:
    df2 = pd.read_csv(racefile_path,encoding="UTF-8")

# df2を複数のTableに分割
dfA = df2[['1 日付','2 開催','3 レース','4 レース名','5 条件','6 コース','7 天候','8 馬場状態','9 発走時刻']]
dfB = df2[['着順','枠番','馬番','馬名','性齢','斤量','騎手','タイム','着差','通過','上り','単勝','人気','馬体重','調教師','馬主','賞金(万円)']]

dfB2 = dfB[:-3]
dfC = dfB[-2:]
print(dfC)

dfC2 = dfC[['着順','枠番']]
print(dfC2)

# dfAのデータ行のみ抽出
row_num = len(df2)-3
print(row_num)

# データ行以外の行番号をリスト化
row_list = [row for row in range(0,row_num + 3) if not row==row_num]
print(row_list)

dfA2 = dfA.drop(dfA.index[row_list])
dfA3 = dfA2.rename(columns={'1 日付': '日付','2 開催': '開催','3 レース': 'レース','4 レース名': 'レース名','5 条件': '条件','6 コース': 'コース','7 天候': '天候','8 馬場状態': '馬場状態','9 発走時刻': '発走時刻'})

dfB3 = dfB2.fillna('')
print(dfB3.dtypes)

# 中(止)、除(外)、取(消)への対応
try:
    dfB3['着順'] = pd.to_numeric(dfB3['着順'], downcast='signed')
except Exception as e:
    print(e)

dfB3['枠番'] = pd.to_numeric(dfB3['枠番'], downcast='signed')
dfB3['馬番'] = pd.to_numeric(dfB3['馬番'], downcast='signed')
dfB3['人気'] = pd.to_numeric(dfB3['人気'], downcast='signed')
print(dfB3.dtypes)

html_string = '''
<html>
    <head>
        <meta charset="UTF-8">
        <title>{raceID}</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <div class="container">
            {tableA}
            {tableB}
            {tableC}
        </div>
    </body>
</html>.
'''

with open(html_file,'w') as f:
    f.write(html_string.format(tableA=dfA3.to_html(index=False),tableB=dfB3.to_html(index=False),tableC=dfC2.to_html(index=False,header=False),raceID=raceID))

[Java] 81 Swing 19 JEditorPaneハイパーリンク・クリック後のHTMLファイル作成 table分割

CSVファイル由来のTableを3つに分割し、縦に並べたHTMLファイルを作成しました。

大分見栄えが良くなりました。あともう少しです。

CSVデータを簡単にHTMLにしてくれるpandasは本当に頼りになるツールです。他のスクリプト言語でpandasに相当するものは存在するのでしょうか。

<CSVファイルの読み込み以降>

try:
    df2 = pd.read_csv(racefile_path,encoding="shift_JIS")
except UnicodeDecodeError:
    df2 = pd.read_csv(racefile_path,encoding="UTF-8")

# df2を複数のTableに分割
dfA = df2[['1 日付','2 開催','3 レース','4 レース名','5 条件','6 コース','7 天候','8 馬場状態','9 発走時刻']]
dfB_pre = df2[['着順','枠番','馬番','馬名','性齢','斤量','騎手','タイム','着差','通過','上り','単勝','人気','馬体重','調教師','馬主','賞金(万円)']]

dfB = dfB_pre[:-3]
dfC_pre = dfB_pre[-2:]
print(dfC_pre)

dfC = dfC_pre[['着順','枠番']]
print(dfC)

# dfAのデータ行のみ抽出
row_num = len(df2)-3
print(row_num)

# データ行以外の行番号をリスト化
row_list = [row for row in range(0,row_num + 3) if not row==row_num]
print(row_list)

dfA2 = dfA.drop(dfA.index[row_list])

html_string = '''
<html>
    <head>
        <meta charset="UTF-8">
        <title>{raceID}</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <div class="container">
            {tableA}
            {tableB}
            {tableC}
        </div>
    </body>
</html>.
'''

with open(html_file,'w') as f:
    f.write(html_string.format(tableA=dfA2.to_html(index=False),tableB=dfB.to_html(index=False),tableC=dfC.to_html(index=False,header=False),raceID=raceID))

[Java] 80 Swing 18 JEditorPaneハイパーリンク・クリック後のHTMLファイル作成 CSS他

Python外部プログラムによりCSVファイルを2つのtableに分割し、これらを縦に並べたHTMLファイルにしました。レイアウトはCSSファイルで設定しています。

ここからheaderの数字やNaNを削除、小数を整数化、列幅設定など体裁を整えていきます。

JavaScriptのElectronでCSSを少し学んだことがここで役に立ちました。

import glob,csv,re
import pandas as pd

paths = glob.glob('/*.csv')
paths2 = sorted(paths)
csvfile = paths2[-2]

df = pd.read_csv(csvfile,encoding='UTF-8')

race_count = len(df)
print("レース数 " + str(len(df)))

list_raceID = df['raceID'].tolist()

pathsB = glob.glob('/*.html')
pathsB2 = sorted(pathsB)
html_file = pathsB2[-1]

# ファイル名からレース番号を抽出
race_num = html_file.split(".")[0][-3:]
print(race_num)

raceID = list_raceID[int(race_num) -1]
print(raceID)

# racefileパスを作成する
year = raceID[1:5]
course = raceID[5:7]
kai =  raceID[7:9]
racefile = "race" + raceID[1:] + ".csv"
racefile_path = f"/race/{year}/{course}/{kai}/{racefile}"

try:
    df2 = pd.read_csv(racefile_path,encoding="shift_JIS")
except UnicodeDecodeError:
    df2 = pd.read_csv(racefile_path,encoding="UTF-8")

# df2を2つに分割
dfA = df2[['1 日付','2 開催','3 レース','4 レース名','5 条件','6 コース','7 天候','8 馬場状態','9 発走時刻']]
dfB = df2[['着順','枠番','馬番','馬名','性齢','斤量','騎手','タイム','着差','タイム指数','通過','上り','単勝','人気','馬体重','調教タイム','厩舎コメント','備考','調教師','馬主','賞金(万円)']]

# dfAのデータ行番号を算出
row_num = len(df2)-3
print(row_num)

# データ行以外の行番号をリスト化
row_list = [row for row in range(0,row_num + 3) if not row==row_num]
print(row_list)

# データ行以外を削除
dfA2 = dfA.drop(dfA.index[row_list])

html_string = '''
<html>
    <head>
        <meta charset="UTF-8">
        <title>{raceID}</title>
        <link rel="stylesheet" href="style.css">
    </head>
    <body>
        <div class="container">
            {tableA}
            {tableB}
        </div>
    </body>
</html>.
'''

with open(html_file,'w') as f:
    f.write(html_string.format(tableA=dfA2.to_html(index=False),tableB=dfB.to_html(index=False),raceID=raceID))
body {
    background-color: #f0f8ff;
}
table {
    margin: 30px 10px 30px 10px;
}
.container {
    display: block;
}
.dataframe{
    background-color: #fffacd;
}

[Java] 79 Swing 17 JEditorPaneハイパーリンク・クリック後のHTMLファイル作成 Python外部プログラム

前回の続きです。

Java-Swingアプリにて選択したレース結果のHTMLファイルを作成するPythonコードです。作成されたHTMLファイルは前回記事にあるMainクラスによりブラウザに表示されます。

このコードではCSVファイルの全内容がtableになるため、適宜加工が必要になります。tableを分割するなどして整形してから、cssファイルで徐々に見栄えを良くしていくつもりです。

import glob
import pandas as pd

paths = glob.glob('/*.csv')
paths2 = sorted(paths)
csvfile = paths2[-2]

df = pd.read_csv(csvfile,encoding='UTF-8')

race_count = len(df)
print("レース数 " + str(len(df)))

list_raceID = df['raceID'].tolist()

pathsB = glob.glob('/race/*.html')
pathsB2 = sorted(pathsB)
html_file = pathsB2[-1]

# 空ファイル名からレース番号を抽出(Javaとの連携箇所)
race_num = html_file.split(".")[0][-3:]
print(race_num)

raceID = list_raceID[int(race_num) -1]
print(raceID)

# racefileパスを作成する
year = raceID[1:5]
course = raceID[5:7]
kai =  raceID[7:9]
racefile = "race" + raceID[1:] + ".csv"
racefile_path = f"/race/{year}/{course}/{kai}/{racefile}"

print(f"year {year}")
print(f"course {course}")
print(f"kai {kai}")
print(f"racefile {racefile}")
print(f"racefile_path {racefile_path}")

df2 = pd.read_csv(racefile_path,encoding="shift_JIS")

html_string = '''
<html>
    <head><meta charset="UTF-8">
    <title>TEST</title>
    </head>
    <body>
        {table}
    </body>
</html>.
'''

with open(html_file,'w') as f:
    f.write(html_string.format(table=df2.to_html(index=False)))

[Java] 70 Swing 10 PythonによるCSVファイル集計 距離着別度数

芝とダートの距離着別度数を表示させました。

<該当箇所のみ>

# 距離着別度数
list_コース = df['コース'].tolist()

list_距離 = list()
for コース in list_コース:
    距離 = re.sub("\\D", "", コース)
    list_距離.append(int(距離))

listT1_order = list() # 芝1400m未満
listT2_order = list() # 芝1400-1699m
listT3_order = list() # 芝1700-2099m
listT4_order = list() # 芝2100-2499m
listT5_order = list() # 芝2500m以上

listD1_order = list() # ダ1400m未満
listD2_order = list() # ダ1400-1699m
listD3_order = list() # ダ1700-2099m
listD4_order = list() # ダ2100m以上

for 距離,コース,着順 in zip(list_距離,list_コース,list_着順):
    if "芝" in コース:
        if 距離 < 1400:
            listT1_order.append(着順)
        elif 1400 <= 距離 < 1700:
            listT2_order.append(着順)
        elif 1700 <= 距離 < 2100:
            listT3_order.append(着順)
        elif 2100 <= 距離 < 2500:
            listT4_order.append(着順)
        else:
            listT5_order.append(着順)
    else:
        if 距離 < 1400:
            listD1_order.append(着順)
        elif 1400 <= 距離 < 1700:
            listD2_order.append(着順)
        elif 1700 <= 距離 < 2100:
            listD3_order.append(着順)
        else:
            listD4_order.append(着順)

# 芝1400m未満
着順1_T1 = len([i for i in listT1_order if i == 1])
着順2_T1 = len([i for i in listT1_order if i == 2])
着順3_T1 = len([i for i in listT1_order if i == 3])
着順外_T1 = len([i for i in listT1_order if i > 3])

着別度数_T1 = f"{着順1_T1}-{着順2_T1}-{着順3_T1}-{着順外_T1}"
print("着別度数_T1 " + 着別度数_T1)

<以下略>