ラベル Stream の投稿を表示しています。 すべての投稿を表示
ラベル Stream の投稿を表示しています。 すべての投稿を表示

2021年5月15日土曜日

トランザクションデータのグループ化(JavaとPython)

    【what is this】トランザクションデータなど、複数のカラム(キー)からなるデータを、特定のいくつかのカラムについて、階層的にグループ化したい場合があります。JavaとPythonを使って、簡単な例で試してみます。

 本記事で扱う小さなデータ(csvファイル)とソースコード(JavaとNotebook形式Python)はこちらにありますので、よろしければお使い下さい。

例題:トランザクションデータ(通貨取引)のグループ化
 何をしたいのかを、図1で説明します。図1(a)は、参考資料[1]のcsvデータを若干編集したものです。先頭行は、3つのカラム名(City, Currency, Value)を示しています。2行目以降のトランザクションを集約して、右側の(b)に示すように、取引所(City)でグループ化し、さらに通貨(Currency)毎の取引額(Value)の平均値を求めたい。この処理は、初歩的なプログラミングでも可能ではありますが、恐らく、込み入ったものになるでしょう。ここでは、分かりやすく、効率的なプログラムにしたいのです。


JavaのStream、groupingByの利用
 図2に示したJavaプログラムは、StreamとCollectionのチュートリアルである参考資料[1]を参考にしています。まず、1〜2行目で上記のcsvデータを読み込み、3行目でトランザクションを3つのカラム対応のデータに分割しますが、データの先頭行は不要なので4行目のfilterで削除します。5行目では、各トランザクションに対するオブジェクトを生成しています。そのクラスの定義は(b)にあります。このオブジェクトのプロパティを利用して、6〜7行目で、Cityについてグループ化し、さらにCurrencyについて纏めてそれらの平均値を得ています。ストリームに対するgroupingByが2重に適用されているところがポイントです。ここで、例えば、「Tranz::getCity」は、トランザクションオブジェクトに対して、一斉にクラスTranzのメソッドを適用する(Cityデータを得る)ことを意味します。8〜11行目は結果の出力表示です。


 1〜7行目までの、2重のグループ化では、if文もforループ文も使われておらず、処理の流れを把握しやすいのが魅力です。実行結果は、図1(b)のようになります。

 Pythonのpandas、groupbyの利用
 次に同じことを、資料[2]を参考にしてPythonでやってみます。グルーピングの考え方はJavaの場合と同じですが、Pythonでの記述量は、図2(a)のように大幅に少なくできます。実質1行(4〜5行目に渡る)で、右側の(b)の実行結果が得られます!素晴らしいですね。PythonのモジュールPandasを使っており、そのなかのgroupbyが効果的に働いています。そして、Javaの場合に切り捨てた先頭行のカラム名(City, Currency, Value)が、自動的に内部で生成されるオブジェクトに対応しています。


 このように、PythonのPandasは効率的プログラミングに貢献しています。しかしながら、これで全面的にPythonの勝利ということではないでしょう。Javaの場合は、明示的に生成したオブジェクトと一連の処理がstreamとして分かりやすいという捨てがたい魅力があります。また、JavaのStream(とそしてラムダ式)は、マルチコアマシン上での並列実行性能を高めるためにあるとも言われますので、大規模データ処理の場合の性能比較も楽しみになります。

[参考資料]
[1] Raoul-Gabriel Urma, "Java SE8ストリームを使用したデータ処理(パート1 & パート2)", Oracle.com/JavaMagazine, March/April, 2014.
[2] Soner Yıldırım, "3 Python Pandas Tricks for Efficient Data Analysis",
https://towardsdatascience.com/3-python-pandas-tricks-for-efficient-data-analysis-6324d013ef39

2020年6月19日金曜日

植物に関する自由記述のJSON化とJavaラムダ式とストリーム(B)

前報(A)の続編です。

(2020-6-21, [検索例(その3)]を追加しました。)

今回の進展
 約3,000行の自然言語による自由形式記述(参考文献[1]にある、植物の一行記述)から、その内容を反映するJSONテキストを自動生成しています。原文に対して係り受け解析を行い(CaboChaにより)、それに基づいてJSONを生成します。係り受け解析結果とJSON生成結果の妥当性検査と、それにもとづいた原文の一部変更という作業を続けてきましたが、このほど終了しました。
 まだまだの状態(JSON自動生成のバージョンはVersion 0.5)ですが、一通りできましたので、以下のとおり、再度いくつかの検索を行ってみました。

自動生成JSONテキストに基づく植物の検索例
 最初の例は、「葉が"倒披針"を含み、花が"白"または"紫"を含む植物」です。検索する主要部は下図のように、Javaの1ステートメントですみます。図中で、jsonStream1は、自動生成したJSONファイルをストリーム化したものです。メソッドbQやpPは小生作成のものです。妥当な検索結果が得られているはずです。

 
 次の例は、「果実のタイプ(type)」を列挙するというものです。上記のその(1)では、.filterと.forEachを使いましたが、ここでは、.mapと.collectを使っている点が違います。概ね妥当(係り受け解析結果の解釈に一部少しの不具合がありますが)な結果のようです。すなわち、このデジタル植物写真集に現れる果実のタイプを概ね列挙しているはずです。


 最後の例は、植物の区分(カテゴリ)毎に"葉"の特徴の記述を集約したものです。多少、処理は複雑にはなりますが、JavaのStreamを処理する強力なgroupingByメソッドのおかげで、見通しのよいコードが書けます。



今後は...
 以上のとおり、植物の葉、花、果実に関するいろいろな検索が少し楽にできるようになったと思います。一方、現状では「穂」や「樹皮」や「茎や根」に関しては、まだJSON生成の対象としていません。今後検討したいと思います。

参考資料
[1] 渡辺 坦:植物の名前を探しやすいデジタル植物写真集
http://plantidentifier.ec-net.jp

2020年6月14日日曜日

植物に関する自由記述のJSON化とJavaラムダ式とストリーム(A)

本記事は、(その3)の続編ですが、少しタイトルを変更しました。

今回の問題設定
 参考資料[1]には、植物を見つけるための1行記述が2,965行(ただしこのうち849行は別名)掲載されています。すなわち、実質約2,100種の植物が掲載されています。そのうちの2例を図1に示します。ここで、例えば、「葉に"楕円"を含み、花に"白"を含む植物」と、そうではなく「果に"楕円"を含み、花に"白"を含む植物」を見つけたいとします。


 単にキーワードとして"楕円"や"白"を含む行を探索するのでは、明らかに妥当な結果が得られません。そのため、自由記述文に形態素解析と係り受け解析を施し、それを基に適切にJSONテキストを生成し、それを使って探索すべきということになりました。

係り受け解析とそれに基づくJSON化は容易か?
 上記のようにして、係り受け解析結果をJSON化することは、実際に行ってみるとそう簡単ではありませんでした。それは、係り受け解析結果が、原文の意味とは異なるケースが少なからずあるからです。その多くの場合、原文に句読点を補う(1文に含まれる複数の単文の区切りを明確にする)こと等で解決しますが、時にはどうしても原文を変更せざるを得ませんでした。その作業は、1行づつ人手で確認しながら進める必要がありました。約3,000行ありますので、1日100行づつ根気強く、確認変更作業を進めています。約1ヶ月かかりますが、まもなく完了します!

 自由に書かれた文の自然言語解析には色々な困難があります。係り受け解析も、簡単なルールだけでは処理仕切れず、機械学習を行っているはずです。人工知能を搭載して、華々しく街へ繰り出した自動運転車もすでに死亡事故を何件か起こしています。学習データの周到な準備は必然ですし、人手による評価修正のフィードバックが必要な状況は続くでしょう。今回のように、3,000件くらいやってみてようやく、自然言語処理の本質が少し見えた来たような気がします。

Javaで自然言語解析する良さがここに現れた
 このように、まだ試行途中なのですが、これまでの作業結果をもとに、上記で設定した問題をやってみました。すなわち、以下の探索を可能にするJavaプログラムを作成しました。
 (1)葉に"楕円"を含み、花に"白"を含む植物
 (2)果に"楕円"を含み、花に"白"を含む植物


 詳しいことは略しますが、図2において、jsonStreamは、生成したJSONテキストをストリーム(stream)化したものです。このストリームの中味は、JSONオブジェクトです。そうなると、ラムダ式を使ったfilterや終端処理としてのforEachの出番です!Javaを使った自然言語処理の良さがここにも現れた気がします。

生成したJSONテキストの概要
 未完成ですが、図3のようなJSONテキストが、係り受け解析結果から自動生成されましたので、ご参考までにその一部をご紹介します。(このJSONテキストは、整形すると全体で約55,000行になります。小生の研究用に生成したものですので、当面、公開はしません。)


参考資料
[1] 渡辺 坦:植物の名前を探しやすいデジタル植物写真集
http://plantidentifier.ec-net.jp

2019年1月1日火曜日

新年にちなんでAndroidでカレンダーアプリを作る

みなさま、明けましておめでとうございます。

今年も、拙文ですが、ここに話題を書いて行こうと思っています。新年にちなんで、何か小さなアプリを作ってみたいと思います。カレンダーを眺めていたら、日にちの曜日が同一となっている月が幾つかあります。そこで、月初めの曜日をキーとして、月をグループ化するアプリを作ってみます。
【英語版はこちらにあります】

月初めの曜日が同じ月をグループ化する

実用性には乏しいミニアプリなのですが、以下の5つの「こだわり」を持って作ります。

【1】Android用に、アプリのロジックは、Javaで作る。
【2】Java8のラムダ式とストリーム、改訂日付クラスを用いる。
【3】GUIはApp Inventorで作り、そこからJavaを起動する。
【4】他のアプリにも適用できる汎用的な枠組みとする。
【5】ActivityStarterをカスタマイズして新規ブロックを作る。

まず、【1】と【2】ですが、最近のAndroidでは、Java8の機能が使えることが分かりました。そこで、ラムダ式とストリームを使って、できるだけ簡潔にこのアプリを書いたつもりです。そのロジック部は、以下の通りです。曜日や月の名前は英語ではなく、日本語にすることもできました。本質的な部分は、Mapオブジェクトmpへの代入文1つだけで済んでいます。このmpの要素は、 [曜日, 初日がその曜日である月のリスト]のペアとなります。


次に、【3】と【4】です。上記のようなJavaプログラムは、App InventorのActivity Starter機能(ブロック)を使って、App Inventorから呼び出すことができます。ここでも、それを使うのですが、できるだけ、汎用的な枠組みにするため、App Inventor側とJava側の両方のひな形を用意しました。Java側には、入力処理部と出力処理部を予め備えておき、上図のようなロジックの記述部だけを書き換えるだけで、ほぼ済むようにしました。また、App Inventor側も、下図のような、他の多くのアプリにも適用できるデザインにしました。

Javaプログラムを呼び出す汎用的なApp Inventorアプリ

最後の【5】ですが、上記の汎用性を考えたことにより、Activity Starterに対して、入力データやパラメータの受け渡しを多少変えたくなりました。そこで、それらに関するカスタマイズを行い、新たなブロックを作りました。以下がそれらのブロックです。Java側との入出力は、テキストファイルを介して行うことにしていますが、入力関しては、入力ファイルのパスを渡す場合と、テキストデータを直接渡す場合の2とおりを選べるようにしました。以下にあるSetupブロックの"isFile"でその選択ができます。

新規作成App Inventorブロック(Activity Starterのカスタマイズ版)
この新規ブロックを使って作ったApp Inventorのプログラムの全体は以下のとおりです。

新規作成ブロックを使ったApp Inventorプログラム

【注】AndroidのJava8対応について
Android 5.0(APIレベル22)以下では、Java7対応であり、Java8は使えません。Android 6.0(APIレベル23)ではラムダ式の一部などは使えますが、ストリームも含めたフル機能を使うには、Android 8.0(APIレベル26)以上が必要のようです。

2018年8月29日水曜日

Javaの教科書サポートページに当方の解説資料を掲載していただきました

 Javaプログラミングの書籍は多数あるのですが、そのうち下記の書籍は、Java教科書として広く使われています。神奈川工科大学 情報工学科でも採用されています。現在は第3版ですが、第1版(2000年10月発行)、第2版(2007年月発行)なので、約18年間の実績があります。その間、Javaでは幾つかの大きな改訂がありましたが、それに対応して来られました。

 当方では、この第3版で学ぶに当たっての参考資料(pdf版60ページ)を作成していました。それを、著者の立木秀樹先生(京都大学)により、下記の教科書サポートページに掲載(資料ファイルへのリンク設置)していただきました。皆様にもご活用戴ければ嬉しいです。

https://www.i.h.kyoto-u.ac.jp/users/tsuiki/javaEveryone3/index.html
(このwebページの「リンク」をご覧ください。)