スピード指数を出すには、場所と距離ごとの標準タイムが必要だ。しかし、距離による時間差、距離による時間差(2)などで書いてきたが、500万以下、1000万以下クラスで同じ距離のレースが何度も行われているわけではないし、雨が降ると一気に走破タイムが変わる。それに、この記事に書いたようにオープンしかないようなレースもある。スピード指数系の予想ソフトを作る人は、ここをどのように適切にするのか、それがポイントになるだろう。逆に言えば、ここに恣意的な操作を施すことによって、それなりの結果を得られるようにすることもできると考えられる。また、開催日ごとの馬場の差を計算に入れるための馬場指数についても同じようなことが言える。馬場指数は、その日に行われたレースのタムから決めることになるだろうが、結局のところ、馬場の状態だけでなく、ペースなどいろいろな要因から変わってくるため、調整するしかない。ここも恣意的な操作が入る部分である。ここの目利きが、その予想ソフトの強さに影響する。
つまり、標準タイムと馬場指数は過去のレースからの計算のみで算出することはできない。過去のレース結果を参考にして、そこから経験等をもとに調整することが必要だ。だからこそ、この部分が売り物になるのだろう。西田式スピード指数のサイトでは、標準タイムと馬場指数が有料で手に入れられる。もう少し、自動的な計算のみで指数を出せないものか。
IT系リサーチャー。最近はブロックチェーン関連に従事。 2019年の再開後は、技術系の話を書こうかね。 2014年以前は、競馬予想ソフト、絵本とAndroid Marketに公開したアプリの話がメインの日常をつづったブログだった。
2014年8月10日日曜日
2014年8月9日土曜日
データベースを使う(4)
データを取り出すのは簡単だ。SQLのselectを使えばいいだけ。下のような形で、馬名で指定する馬の一定期間内のデータを取得することが出来る。
public List<HorseData> select(String horsename, Date mindate, Date maxdate) {
try {
PreparedStatement ps = conn.prepareStatement("select * from Horse where name = ? and date < ? and date >= ? order by date DESC");
ps.setString(1, horsename);
ps.setDate(2, new java.sql.Date(maxdate.getTime()));
ps.setDate(3, new java.sql.Date(mindate.getTime()));
ResultSet rs = ps.executeQuery();
return readResultSet(rs);
} catch (SQLException se) {
for (SQLException e = se; e != null; e = e.getNextException()) {
TLog.e("%s: %s%n", e.getSQLState(), e.getMessage());
}
}
return null;
}
private List<HorseData> readResultSet(ResultSet rs) {
List<HorseData> list = new ArrayList<HorseData>();
try {
while (rs.next()) {
HorseData hd = new HorseData();
hd.name = rs.getString("name");
hd.term = rs.getInt("term");
hd.place = rs.getInt("place");
hd.day = rs.getInt("day");
hd.rnum = rs.getInt("rnum");
hd.date = new Date(rs.getDate("date").getTime());
hd.frame = rs.getInt("frame");
hd.number = rs.getInt("number");
hd.order = rs.getInt("ordernumber");
hd.time = rs.getInt("time");
hd.popularity = rs.getInt("popularity");
hd.weight = rs.getInt("weight");
hd.loadweight = rs.getFloat("loadweight");
hd.threefurlong = rs.getFloat("threefurlong");
hd.odds = rs.getFloat("odds");
hd.setPassorder(rs.getString("passorder"));
list.add(hd);
}
} catch (SQLException se) {
for (SQLException e = se; e != null; e = e.getNextException()) {
TLog.e("%s: %s%n", e.getSQLState(), e.getMessage());
}
}
return list;
}
2014年8月8日金曜日
書評: ある奴隷少女に起こった出来事
奴隷だった著者による自伝。著者のハリエットは1813年生まれ。リンカーンが奴隷解放宣言をしたのが1862年なので、49歳の頃ということになる。アメリカの南部で奴隷があったことは知識として知っていても、具体的にどういうものなのか知らない人は多いだろう。僕もそうだった。
著者が、奴隷として使えていた家から抜け出し、自由を得るまでの話であるが、それまでの紆余曲折が書かれている。その時々に最善を考えて行動しているのだろうが、論理的にそう思えないところが数々あるため、小説として読んでしまうと少し辛いかもしれない。著者の実質的な所有者であるドクターフリントがストーカー気質で精神的な嫌がらせはしつくすのに、力尽くでということはしないという不思議な性格。また、著者が、祖母の家の屋根裏で7年間過ごすというのはすさまじい。実際にあったことということに驚くしかない。
奴隷の売買や相続による所有者の変更や、母が奴隷の場合は子供も奴隷になるという法律、自由州に逃げたとしても連れ戻される法律、いろいろな形で絡まり合い、読みどころの多い本である。
著者が、奴隷として使えていた家から抜け出し、自由を得るまでの話であるが、それまでの紆余曲折が書かれている。その時々に最善を考えて行動しているのだろうが、論理的にそう思えないところが数々あるため、小説として読んでしまうと少し辛いかもしれない。著者の実質的な所有者であるドクターフリントがストーカー気質で精神的な嫌がらせはしつくすのに、力尽くでということはしないという不思議な性格。また、著者が、祖母の家の屋根裏で7年間過ごすというのはすさまじい。実際にあったことということに驚くしかない。
奴隷の売買や相続による所有者の変更や、母が奴隷の場合は子供も奴隷になるという法律、自由州に逃げたとしても連れ戻される法律、いろいろな形で絡まり合い、読みどころの多い本である。
2014年8月6日水曜日
データベースを使う(3)
データベースを使う(1)で作ったテーブルに、馬のデータを差し込んで行く。普通にSQLのinsertを使えばいいだけ。executeUpdate()を使えば、Primary Keyが同じ場合はエラーでなく、上書きされる。これをYahoo競馬から取得したデータをすべてデータベースに登録し直し。これで、使いやすくなったはず。
public boolean insert(Horse horse, int term, int place, int day, int rnum, Date date) {
try {
final String sql = "insert into Horse values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
final PreparedStatement ps = conn.prepareStatement(sql);
ps.setString(1, horse.name);
ps.setInt(2, term);
ps.setInt(3, place);
ps.setInt(4, day);
ps.setInt(5, rnum);
ps.setDate(6, new java.sql.Date(date.getTime()));
ps.setInt(7, horse.frame);
ps.setInt(8, horse.number);
ps.setInt(9, horse.order);
ps.setInt(10, horse.time);
ps.setInt(11, horse.popularity);
ps.setInt(12, horse.weight);
ps.setFloat(13, horse.loadweight);
ps.setFloat(14, horse.threefurlong);
ps.setFloat(15, horse.odds);
ps.setString(16, horse.getPassorder());
ps.executeUpdate();
} catch (SQLException se) {
for (SQLException e = se; e != null; e = e.getNextException()) {
TLog.e("%s: %s%n", e.getSQLState(), e.getMessage());
}
}
return true;
}
2014年8月4日月曜日
データベースを使う(2)
テーブルを作るかどうかを判定するには、データを取ってみたらいいようだ。
ResultSet rs = null;
try {
final Statement s = conn.createStatement();
rs = s.executeQuery("select count(1) from Horse");
} catch (SQLException se) {
final String state = se.getSQLState();
if (state.equals("42X05")) {
makeTable(conn);
} else {
for (SQLException e = se; e != null; e = e.getNextException()) {
TLog.e("%s: %s%n", e.getSQLState(), e.getMessage());
}
}
} finally {
if (rs != null) try {rs.close();} catch (Exception e) {};
}
makeTableの先は、データベースを使うで書いたcreate tableを呼び出している。
2014年8月3日日曜日
データベースを使う
すべてオンメモリで動かせば、データベースを使う必要はないだろう。と、思ったが、結構でかい。全部読み込んだらエラーが出る。ヒープ領域を大きくすればいいのかもしれないが、すべてをメモリに読み込むのは止めることにした。それにあたり、Json形式でファイルを保存することにしていたが、読み込み時にデータをしぼることを考えれば、やはりデータベースを使うほうがいいだろう。なお、PCではなく、Google Appを使うことを考えたら、BigTableに置き換えることを想定したほうがいいのだが、普通にSQLを使う。JavaではDerbyを使うのがいいようだ。で、ライブラリに、ダウンロードしたderby.jarを追加した。
String CREATEHORSETABLE =
"create table Horse " +
"(name varchar(20) NOT NULL, term smallint NOT NULL, " +
"place smallint NOT NULL, day smallint NOT NULL, " +
"rnum smallint NOT NULL, date date NOT NULL, frame smallint, " +
"number smallint, ordernumber smallint, time smallint, " +
"popularity smallint, weight smallint, loadweight real, " +
"threefurlong real, odds real, passorder char(20), " +
"PRIMARY KEY(name, date))";
Connection conn = DriverManager.getConnection("jdbc:derby:/Users/tkydevelop/Documents/workspace/HorseRaceAnalyzer/db;create=true");
Statement s = conn.createStatement();
s.execute(CREATEHORSETABLE);
のようにしてテーブルを作成した。
2014年8月2日土曜日
Jsonで書き込みと読み出し
Yahoo競馬から取得したデータをjson形式でファイルに保存することにした。jsonのライブラリとして、jacksonを使った。Annotations, Streaming API, DataBindのライブラリを追加した。
ObjectMapper om = new ObjectMapper();
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.FIELD, Visibility.ANY)
.setVisibility(PropertyAccessor.CREATOR, Visibility.NONE)
.setVisibility(PropertyAccessor.SETTER, Visibility.NONE)
.setVisibility(PropertyAccessor.GETTER, Visibility.NONE)
.setVisibility(PropertyAccessor.IS_GETTER, Visibility.NONE);
om.writeValue(file, list);
writeValueを使うとオブジェクトの属性値がそのまま書き出される。加えて、たとえば、getXXXX的な名前の関数の値も書き出されてしまう。そのため、setVisibilityを使って、それらを書き出さないように変更した。
一方で読み込みをしようとしても、うまくオブジェクトに読み込むことができなかった。仕方ないので、
JsonNode rootNode;
rootNode = om.readTree(new File(filename));
for (JsonNode node: rootNode) {
Race race = new Race();
race.date = new Date(node.get("date").longValue());
のような形で、リストを繰り返しながら読み込んだ。
登録:
投稿 (Atom)