[Java] 69 Swing 09 PythonによるCSVファイル集計 条件毎の着別度数

芝とダートの着別度数を算出し、プロフィール隣のJTextAreaに表示しました。あと馬場状態や距離の着別度数は必須でしょう。

芝とダートで活躍した実力馬といえばホクトベガですが地方競馬のデータがこちらにないので、中央の芝とダートにデータがあるナリタハヤブサを検索例にしました。ここまで書いたところでアグネスデジタルを思い出しました。

import glob,csv
import pandas as pd

paths = glob.glob('/*.csv')
print(paths)

paths2 = sorted(paths)
print(paths2)

csvfile = paths2[-1]
print(csvfile)

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

prize = df['賞金'].sum(skipna=True).round(1)
print(f"獲得賞金 {prize}")

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

list_着順 = df['着順'].tolist()
着順1 = len([i for i in list_着順 if i == 1])
着順2 = len([i for i in list_着順 if i == 2])
着順3 = len([i for i in list_着順 if i == 3])
着順外 = len([i for i in list_着順 if i > 3])

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

list_馬場 = df['馬場状態'].tolist()

list_turf_order = list()
list_dirt_order = list()
for course,order in zip(list_馬場,list_着順):
    if "芝" in course:
        list_turf_order.append(order)
    else:
        list_dirt_order.append(order)

着順1_t = len([i for i in list_turf_order if i == 1])
着順2_t = len([i for i in list_turf_order if i == 2])
着順3_t = len([i for i in list_turf_order if i == 3])
着順外_t = len([i for i in list_turf_order if i > 3])

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

着順1_d = len([i for i in list_dirt_order if i == 1])
着順2_d = len([i for i in list_dirt_order if i == 2])
着順3_d = len([i for i in list_dirt_order if i == 3])
着順外_d = len([i for i in list_dirt_order if i > 3])

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

list_output = [{"獲得賞金":prize,"着別度数":着別度数,"芝":着別度数_t,"ダ":着別度数_d}]

# 出力ファイル名作成
filename = csvfile.split(".")[0] + "_agg.csv"

field_name = ['獲得賞金','着別度数','芝','ダ']
with open(filename,'w',encoding='utf-8') as f:
    writer = csv.DictWriter(f, fieldnames = field_name)
    writer.writeheader()
    writer.writerows(list_output)

[Java] 68 Swing 08 外部プログラムの選択 改良版

前回の続きです。switch文の重複部分が気になったので書き直しました。こちらの方がメンテナンス性も優れており断然スマートです。

import java.util.ArrayList;

public class ProcessExecutor {
    public static void exec(String type) throws Exception {
    	System.out.println("ProcessExecutor");

    	// 分類用リスト作成 集計:agg,分析:ana,血統:blo 以降随時追加
    	ArrayList<String> types = new ArrayList<String>();
    		types.add("agg");
    		types.add("ana");

		// cmdリスト作成
		ArrayList<String> cmds = new ArrayList<String>();
    		cmds.add("python HS_csv_agg.py ; echo 'コマンド完了'");
    		cmds.add("python HS_csv_ana.py ; echo 'コマンド完了'");

    	// index番号取得
    	int type_num = types.indexOf(type);
    	System.out.println("index番号 " + type_num);

    	// コマンド選択
    	String cmd = cmds.get(type_num);

		ProcessBuilder p = new ProcessBuilder("sh", "-c", cmd);
        p.redirectErrorStream(true);
        // プロセス開始
        Process process = p.start();
        // プロセス終了まで待機
        process.waitFor();
        int result = process.exitValue();
        System.out.printf("result = %d%n", result);
    }
}

[Java] 67 Swing 07 外部プログラムの選択(switch文)

Java-Swingアプリの集計、分析等はPythonで処理していますが、処理内容によってコードを使い分けるようにしました。

import java.util.ArrayList;

public class ProcessExecutor {
    public static void exec(String type) throws Exception {
    	System.out.println("ProcessExecutor");

    	// 分類用リスト作成 集計:agg,分析:ana,血統:blo 以降随時追加
    	ArrayList<String> types = new ArrayList<String>();
    		types.add("agg");
    		types.add("ana");
    		types.add("blo");

    	// case番号を付番
    	int type_num = types.indexOf(type);
    	System.out.println("case番号 " + type_num);

    	switch(type_num) {
			case 0: // 集計
				String cmd0 = "python HS_csv_agg.py ; echo 'コマンド完了'";
				ProcessBuilder p0 = new ProcessBuilder("sh", "-c", cmd0);
		        p0.redirectErrorStream(true);
		        // プロセス開始
		        Process process0 = p0.start();
		        // プロセス終了まで待機
		        process0.waitFor();
		        int result = process0.exitValue();
		        System.out.printf("result = %d%n", result);
		        break;
			case 1: // 分析
				String cmd1 = "python HS_csv_ana.py ; echo 'コマンド完了'";
				ProcessBuilder p1 = new ProcessBuilder("sh", "-c", cmd1);
		        p1.redirectErrorStream(true);
		        // プロセス開始
		        Process process1 = p1.start();
		        // プロセス終了まで待機
		        process1.waitFor();
		        int result1 = process1.exitValue();
		        System.out.printf("result = %d%n", result1);
		        break;
    	}
    }
}

[Python] 297 数値を丸める(偶数丸め,四捨五入)

Java-Swingアプリの外部プログラムとしてPythonコードを走らせ、pandasにて合計を計算したところ変な小数が発生しました。

原因は不明ですが、放置もできないので数値を丸めました。pandasのround()メソッドは四捨五入ではなく偶数丸めです。偶数丸めとは、丸めるところが5の場合すぐ上の桁が偶数であれば切り捨て、奇数であれば切り上げる処理です。

数値の丸めはJIS Z 8401で規定されていて、規則Aが偶数丸め、規則Bが四捨五入です。つまり、誤差がより小さい偶数丸めの方を推奨しています。銀行が好んで使うため銀行丸めとも呼ばれています。

# 小数点以下の桁数は1桁に設定
prize = df['賞金'].sum(skipna=True).round(1)
print(f"獲得賞金 {prize}")

[Java] 66 Swing 06 PythonによるCSVファイル集計

CSVファイルの内容集計は外部プログラムのPython(pandas)に任せています。

集計コードは以下の通りです。Javaとの格闘で一時げんなりしていましたが、直感的にコーディングできるPythonによって息を吹き返しました。リスト内包表記を書くといつも爽快な気分になります。引き続き頑張っていけそうです。

import glob,csv
import pandas as pd

paths = glob.glob('/*.csv')
print(paths)

paths2 = sorted(paths)
print(paths2)

csvfile = paths2[-1]
print(csvfile)

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

prize = df['賞金'].sum()
print(f"獲得賞金 {prize}")

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

list = df['着順'].tolist()
一着回数 = len([i for i in list if i == 1])
二着回数 = len([i for i in list if i == 2])
三着回数 = len([i for i in list if i == 3])
着外回数 = len([i for i in list if i > 3])

着別度数 = f"{一着回数}-{二着回数}-{三着回数}-{着外回数}"
print("着別度数 " + 着別度数)

list_output = [{"獲得賞金":prize,"着別度数":着別度数}]

# 集計ファイル名作成(集計:aggregate)
filename = csvfile.split(".")[0] + "_agg.csv"

field_name = ['獲得賞金','着別度数']
with open(filename,'w',encoding='utf-8') as f:
    writer = csv.DictWriter(f, fieldnames = field_name)
    writer.writeheader()
    writer.writerows(list_output)

[Java] 65 外部コマンドの実行

Javaにおける配列、リスト、CSVファイルの取り扱いが私にとってはあまりに煩雑なので、外部コマンドにてPythonスクリプトを走らせることにします。

昨日はArrayListをCSVファイルに変換するのに散々痛い目にあって懲りました。JavaでCSVファイルの内容を読み込んで集計するなんてPythonユーザーの私にはかなりの苦行です。

JavaからPythonスクリプトを直接呼び出せないのでコンソールコマンドを使います。戻り値のやりとりはできないため、CSVファイル等を介してデータを出し入れします。

コンソールコマンドを実行するクラスは以下の通りです。

Javaとの実用面での関わりはGUI作成限定になりそうです。好きな言語ではありますが、コーディング快適性や開発速度を考慮しての結論です。

JavaはC言語と同様、実装に使うかどうかはともかく学習対象であることは変わりません。

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.nio.charset.Charset;

public class ProcessExecutor {
    public static void main() throws Exception {
    	System.out.println("ProcessExecutor");

        ProcessBuilder p = new ProcessBuilder("sh", "-c", "python test.py ; echo 'コマンド完了'");

        p.redirectErrorStream(true);

        // コマンドを実行する
        Process process = p.start();

        // 結果を受け取る
        try (BufferedReader r = new BufferedReader(new InputStreamReader(process.getInputStream(), Charset.defaultCharset()))) {
            String line;
            while ((line = r.readLine()) != null) {
                System.out.println(line);
            }
        }
        process.waitFor();
        int result = process.exitValue();
        System.out.printf("result = %d%n", result);
    }
}

[Python] 296 Jython 03 FXMLファイルの読み込み

軽い気持ちで取りかかったら見事にハマりました。

なかなか解決しなかったのは、launchメソッドの2番目の引数とFXMLファイルのパスの書き方です。

いわゆるヌルポ(NullPointerException)から脱するため、Thread.currentThread().getStackTrace()を走らせたり色々調べても解決の糸口を見出せず。

結局、引数はsys.argv、パスはプロジェクトディレクトリ直下の絶対パスでした。JavaではMainファイルからの相対パスになります(スラッシュなしのファイル名のみ)。スラッシュの有り無しは全く意識してませんでした。

EclipseからPyCharmに検討環境を移す寸前でStackOverFlowの英語版にヒントを見つけました。またしても海外のギークに助けられました。

GUI内のカタカナなど2バイト文字が明らかに中華系フォントなので、別途フォント指定が必要ですね。

from javafx.application import Application
from javafx.fxml import FXMLLoader
from javafx.scene import Scene
import sys

class JythonJavafx(Application):
    def start(self, stage):
        root = FXMLLoader.load(self.getClass().getResource('/test.fxml'))
        stage.setScene(Scene(root, 300, 125))
        stage.setTitle("CHARACTER CODE CONVERTOR")
        stage.show()

if __name__ == "__main__":
    Application.launch(JythonJavafx().__class__, sys.argv)
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.BorderPane?>

<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="125.0" prefWidth="300.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1">
    <center>
        <Label text="FXML ロード成功" BorderPane.alignment="CENTER" />
    </center>
</BorderPane>

[Python] 295 Jython 02 JavaFXプロジェクトの移植

JavaFXプロジェクトのJythonへの移植を試みています。

ガワは再現できたので次はFXMLの導入です。

Application.launchの引数でエラーになっていましたが、オブジェクトのクラス__class__で解決しました。

おそらくexe化はできないため、私にとってこのスキルの必要性は高くないです。気が向いた時にのんびり進めていきます。

from javafx.application import Application
from javafx.scene import Scene
from javafx.scene.layout import AnchorPane;

class Main(Application):
    def start(self, stage):
        root = AnchorPane()
        stage.setScene(Scene(root, 300, 125))
        stage.setTitle("CHARACTER CODE CONVERTOR")
        stage.show()

if __name__ == "__main__":
    Application.launch(Main().__class__, [])

[Python] 294 Jython 01 Eclipseでテスト

[macOS Catalina 10.15.7]

過去の遺物になりつつある感が否めないJython(ジャイソン)をたわむれにいじっています。

Hello JythonのPaneを表示させるのに丸1日かかりました。何かエラーになっているようですが、とりあえず良しとします。

PyDev開発元によると最新のEclipse 2021-03はクラッシュしているそうなので、その前の2020-12を使いました。なお2021-03は私の用途ではJython以外で問題なく使えています。

JREはJavaFXがOracle公式にて廃止される直前のJava8(調べると採用されたのは8のみ)、Jythonは最新1つ手前の2.7.1です。Jython 2.7.2はEclipseに導入できませんでした。

設定画像もアップしておきます。

最近はさしあたってコーディングしたいものがなく、ゲームをクリアする感覚で今回のような初心者向きの課題に取り組んでいます。

Javaを扱うようになって2000年代のブログ記事を読んだりしますが、扱っているツールやOS等のバージョン情報がほとんどなくて残念です。まさか2020年代に資料として読まれるとは思ってもいないのでしょう。

[Python] 293 引数が複数あるC言語モジュール

以前うまくいかなかったC言語モジュールを完成させました。

input(引数)とoutput(戻り値)を自在に設定でき、C言語実行ファイルに必須の処理終了検知が不要なので、こちらを常用することになりそうです。

#define PY_SSIZE_T_CLEAN
#include <Python.h>
#include "fnv_function.c"

static PyObject* horse_id(PyObject* self, PyObject* args)
{
    const char* path;
    const char* name;
    uint32_t id;

    if (!PyArg_ParseTuple(args,"ss",&path,&name)){
        return NULL;
    }
    else{
        FILE *fp; // horse_listファイル
        int horseID[10]; // 1 horseID
        uint32_t horse_hash[20]; // 2 馬名ハッシュ
        char horse_name[100]; // 3 検索馬名
        char horse_name0[100]; // 4 馬名
        char status[10]; // 5 稼働
        char gender[10]; // 6 性別
        char hair[10]; // 7 毛色
        char birthday[100]; // 8 生年月日
        char trainer[100]; // 9 調教師
        char owner[100]; // 10 馬主
        char info[100]; // 11 募集情報
        char breeder[100]; // 12 生産者
        char area[50]; // 13 産地
        char price[50]; // 14 セリ取引価格
        char prize_money[50]; // 15 獲得賞金
        char result[50]; // 16 通算成績
        char wining_race[200]; // 17 主な勝鞍
        char relatives[200]; // 18 近親馬

        uint32_t horse_hash_input_int;
        uint32_t horse_hash_int;

        char buf[2000]; // fgets用

        int i=0; // 行番号
        int b=0; // 検索結果有無の識別

        fp = fopen(path, "r");

        while(fgets(buf,2000,fp ) != NULL ) {
            if (i != 0){
                sscanf(buf, " %[^,],%[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %[^,], %s",horseID,horse_hash,horse_name,horse_name0,status,gender,hair,birthday,trainer,owner,info,breeder,area,price,prize_money,result,wining_race,relatives) ;

                horse_hash_int = atoi(horse_hash);
                horse_hash_input_int = fnv_1_hash_32(name);

                if(horse_hash_int - horse_hash_input_int == 0){
                    id = atoi(horseID);
                    b ++;
                    break;
                }
            }
            i ++ ;
        }
        if (b == 0){
            id = 100000000;
        }
        fclose(fp);

        return Py_BuildValue("I", id);
    }
}

static PyMethodDef Horseidmethods[] = {
    {"horse_id", (PyCFunction)horse_id, METH_VARARGS},
    {NULL,NULL,0}
};

static struct PyModuleDef horseid = {
    PyModuleDef_HEAD_INIT,
    "horseid",
    "Python3 C API Module(Sample 1)",
    -1,
    Horseidmethods
};

PyMODINIT_FUNC PyInit_horseid(void)
{
    return PyModule_Create(&horseid);
}