Morpheus ライブラリは、Java 仮想マシン (JVM) 上でのオフライン分析とリアルタイム分析の両方のための大規模なデータセットを含む高性能分析ソフトウェアの開発を容易にするように設計されています。このライブラリはラムダを多用して Java 8 で作成されていますが、すべての JVM 言語でアクセスできます。
例を含む詳細なドキュメントについては、ここを参照してください
Morpheus の中心となるのは、R で最初に普及したものと同様の、 DataFrame
と呼ばれる多用途の 2 次元メモリ効率の高い表形式のデータ構造です。R、Python、Matlab などの動的に型付けされた科学計算言語は研究には最適ですが、十分ではありません。保守が非常に難しく、リファクタリングが危険であるため、大規模な実稼働システムに適しています。 Morpheus ライブラリは、 DataFrame
概念のパワーと多用途性を保持しながら、よりタイプ セーフで自己記述型のインターフェイスのセットを提供することを試みており、これによりコードの複雑さの開発、保守、スケーリングがはるかに容易になります。
Morpheus ライブラリのもう 1 つの利点は、Java 仮想マシンの強力なスレッド機能を考慮して、マルチコア プロセッサ アーキテクチャでのスケーリングが非常に優れていることです。 Morpheus DataFrame
上の多くの操作は、Java 8 Streams と同様に、操作対象のエンティティに対してparallel()
を呼び出すだけでシームレスに並列実行できます。内部的には、これらの並列実装は Fork & Join フレームワークに基づいており、CPU コアが追加されると、特定の種類の操作でほぼ直線的なパフォーマンスの向上が観察されます。
Morpheus DataFrame
は、各列が Morpheus Array
で表される列ストア構造であり、密、疎、メモリ マップされたバージョンなど、多くの実装があります。 Morpheus 配列は最適化されており、ストレージ、アクセス、ガベージ コレクションの観点から見てはるかに効率的であるため、可能な限りプリミティブなネイティブ Java 配列 ( LocalDate
、 LocalDateTime
などの型であっても) によってサポートされています。メモリ マップされた Morpheus Arrays
、まだ実験段階ではありますが、ファイルを基にしたオフヒープ ストレージを使用して非常に大規模なDataFrames
作成できます。
Morpheus DataFrame
の完全な機能セットはまだ進化中ですが、複雑な変換や分析操作を簡単に実行できる強力な API がすでに多数存在します。いくつか例を挙げると、概要統計を計算したり、さまざまな種類の線形回帰を実行したり、主成分分析 (PCA) を適用したりするための標準関数があります。 DataFrame
は行次元と列次元の両方でインデックスが付けられ、どちらかの軸に沿ってデータを効率的に並べ替え、スライス、グループ化、集計できるようになります。
Morpheus は、さまざまなデータ プロバイダーからデータセットをロードするための標準メカニズムを提供することも目的としています。サポートされるデータ ソースのカタログを増やすために、この API がコミュニティに受け入れられることが期待されています。現在、Quandl、連邦準備制度、世界銀行、Yahoo Finance、Google Finance からデータをロードできるようにプロバイダーが実装されています。
ここからアクセスできる自動車の特性のデータセットを考えてみましょう。以下のコードは、この CSV データを Morpheus DataFrame
にロードし、出力重量比 > 0.1 (重量はキログラムに変換) を持つ車両のみを含むように行をフィルターし、高速道路と高速道路間の相対効率を記録する列を追加します。都市走行距離 (MPG) を取得し、この新しく追加された列によって行を降順に並べ替え、最後にこの変換結果を CSV ファイルに記録します。
DataFrame . read (). csv ( options -> {
options . setResource ( "http://zavtech.com/data/samples/cars93.csv" );
options . setExcludeColumnIndexes ( 0 );
}). rows (). select ( row -> {
double weightKG = row . getDouble ( "Weight" ) * 0.453592d ;
double horsepower = row . getDouble ( "Horsepower" );
return horsepower / weightKG > 0.1d ;
}). cols (). add ( "MPG(Highway/City)" , Double . class , v -> {
double cityMpg = v . row (). getDouble ( "MPG.city" );
double highwayMpg = v . row (). getDouble ( "MPG.highway" );
return highwayMpg / cityMpg ;
}). rows (). sort ( false , "MPG(Highway/City)" ). write (). csv ( options -> {
options . setFile ( "/Users/witdxav/cars93m.csv" );
options . setTitle ( "DataFrame" );
});
この例は、Morpheus API の機能的性質を示しています。多くのメソッドの戻り値の型は実際にはDataFrame
であるため、この形式のメソッド チェーンが可能です。この例では、 csv()
、 select()
、 add()
、およびsort()
メソッドはすべてフレームを返します。メソッドが操作する同じフレームの場合もあれば、フィルターまたは操作対象のフレームの浅いコピーである場合もあります。この例の変換されたデータセットの最初の 10 行は次のようになり、新しく追加された列がフレームの右端に表示されます。
インデックス |メーカー |モデル |タイプ |最低価格 |価格 |最高価格 | MPG.city | MPG.ハイウェイ |エアバッグ |ドライブトレイン |シリンダー |エンジンサイズ |馬力 |回転数 |マイルあたりの回転数 |マントランスアベイル |燃料タンク容量 |乗客 |長さ |ホイールベース |幅 |ターンサークル |後部座席の部屋 |ラゲッジルーム |重量 |由来 |作る | MPG(高速道路/市街地) | -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- -------------------------------------------------- 9 |キャデラック |デビル |大 | 33.0000 | 34.7000 | 36.3000 | 16 | 25 |ドライバーのみ |フロント | 8 | 4.9000 | 200 | 4100 | 1510 |いいえ | 18.0000 | 6 | 206 | 114 | 73 | 43 | 35 | 18 | 3620 |アメリカ |キャデラック デビル | 1.5625 | 10 |キャデラック |セビリア |中型 | 37.5000 | 40.1000 | 42.7000 | 16 | 25 |運転手と乗客 |フロント | 8 | 4.6000 | 295 | 6000 | 1985年 |いいえ | 20.0000 | 5 | 204 | 111 | 74 | 44 | 31 | 14 | 3935 |アメリカ |キャデラック セビリア | 1.5625 | 70 |オールズモビル |八十八 |大 | 19.5000 | 20.7000 | 21.9000 | 19 | 28 |ドライバーのみ |フロント | 6 | 3.8000 | 170 | 4800 | 1570年 |いいえ | 18.0000 | 6 | 201 | 111 | 74 | 42 | 31.5 | 17 | 3470 |アメリカ |オールズモビル エイティエイト | 1.47368421 | 74 |ポンティアック |火の鳥 |スポーティ | 14.0000 | 17.7000 | 21.4000 | 19 | 28 |運転手と乗客 |リア | 6 | 3.4000 | 160 | 4600 | 1805年 |はい | 15.5000 | 4 | 196 | 101 | 75 | 43 | 25 | 13 | 3240 |アメリカ |ポンティアック ファイアーバード | 1.47368421 | 6 |ビュイック |ルセイバー |大 | 19.9000 | 20.8000 | 21.7000 | 19 | 28 |ドライバーのみ |フロント | 6 | 3.8000 | 170 | 4800 | 1570年 |いいえ | 18.0000 | 6 | 200 | 111 | 74 | 42 | 30.5 | 17 | 3470 |アメリカ |ビュイック ルセイバー | 1.47368421 | 13 |シボレー |カマロ |スポーティ | 13.4000 | 15.1000 | 16.8000 | 19 | 28 |運転手と乗客 |リア | 6 | 3.4000 | 160 | 4600 | 1805年 |はい | 15.5000 | 4 | 193 | 101 | 74 | 43 | 25 | 13 | 3240 |アメリカ |シボレー カマロ | 1.47368421 | 76 |ポンティアック |ボンネビル |大 | 19.4000 | 24.4000 | 29.4000 | 19 | 28 |運転手と乗客 |フロント | 6 | 3.8000 | 170 | 4800 | 1565年 |いいえ | 18.0000 | 6 | 177 | 111 | 74 | 43 | 30.5 | 18 | 3495 |アメリカ |ポンティアック ボンネビル | 1.47368421 | 56 |マツダ | RX-7 |スポーティ | 32.5000 | 32.5000 | 32.5000 | 17 | 25 |ドライバーのみ |リア |ロータリー | 1.3000 | 255 | 6500 | 2325 |はい | 20.0000 | 2 | 169 | 96 | 69 | 37 | NA | NA | 2895 |米国以外 |マツダ RX-7 | 1.47058824 | 18 |シボレー |コルベット |スポーティ | 34.6000 | 38.0000 | 41.5000 | 17 | 25 |ドライバーのみ |リア | 8 | 5.7000 | 300 | 5000 | 1450 |はい | 20.0000 | 2 | 179 | 96 | 74 | 43 | NA | NA | 3380 |アメリカ |シボレー コルベット | 1.47058824 | 51 |リンカーン |タウンカー |大 | 34.4000 | 36.1000 | 37.8000 | 18 | 26 |運転手と乗客 |リア | 8 | 4.6000 | 210 | 4600 | 1840年 |いいえ | 20.0000 | 6 | 219 | 117 | 77 | 45 | 31.5 | 22 | 4055 |アメリカ |リンカーンタウンカー | 1.44444444 |
Morpheus API には、OLS、WLS、または GLS のいずれかを使用してデータを線形モデルに適合させるための回帰インターフェイスが含まれています。以下のコードは、前の例で紹介したのと同じ車のデータセットを使用し、 EngineSizeでHorsepower を回帰します。このコード例では、以下に示すモデルの結果を標準出力に出力し、回帰直線が明確に表示された散布図を作成します。
//Load the data
DataFrame < Integer , String > data = DataFrame . read (). csv ( options -> {
options . setResource ( "http://zavtech.com/data/samples/cars93.csv" );
options . setExcludeColumnIndexes ( 0 );
});
//Run OLS regression and plot
String regressand = "Horsepower" ;
String regressor = "EngineSize" ;
data . regress (). ols ( regressand , regressor , true , model -> {
System . out . println ( model );
DataFrame < Integer , String > xy = data . cols (). select ( regressand , regressor );
Chart . create (). withScatterPlot ( xy , false , regressor , chart -> {
chart . title (). withText ( regressand + " regressed on " + regressor );
chart . subtitle (). withText ( "Single Variable Linear Regression" );
chart . plot (). style ( regressand ). withColor ( Color . RED ). withPointsVisible ( true );
chart . plot (). trend ( regressand ). withColor ( Color . BLACK );
chart . plot (). axes (). domain (). label (). withText ( regressor );
chart . plot (). axes (). domain (). format (). withPattern ( "0.00;-0.00" );
chart . plot (). axes (). range ( 0 ). label (). withText ( regressand );
chart . plot (). axes (). range ( 0 ). format (). withPattern ( "0;-0" );
chart . show ();
});
return Optional . empty ();
});
================================================= =========================================== 線形回帰の結果 ================================================= =========================================== モデル: OLS R2乗: 0.5360 観測値: 93 R 二乗 (調整済み): 0.5309 DF モデル: 1 F 統計: 105.1204 DF 残差: 91 F 統計量 (確率): 1.11E-16 標準誤差: 35.8717 実行時間(ミリ) 52 ダービン-ワトソン: 1.9591 ================================================= =========================================== インデックス |パラメータ | STD_エラー | T_STAT | P_値 | CI_LOWER | CI_UPPER | -------------------------------------------------- -------------------------------------------- インターセプト | 45.2195 | 10.3119 | 4.3852 | 3.107E-5 | 24.736 | 65.7029 | エンジンサイズ | 36.9633 | 3.6052 | 10.2528 | 7.573E-17 | 29.802 | 44.1245 | ================================================= ===========================================
英国政府のオープンデータ イニシアチブを通じて、1995 年から現在までの英国のすべての住宅不動産取引記録にアクセスすることが可能です。データは CSV 形式で表示され、取引日、支払った価格、完全修飾住所 (郵便番号を含む)、物件タイプ、リースタイプなどの情報を含む多数の列が含まれています。
これらの CSV ファイルを Amazon S3 バケットからロードする関数を作成することから始めましょう。CSV ファイルは 1 年に 1 つのファイルに保存されるため、それに応じてパラメーター化された関数を提供します。分析の要件を考慮すると、ファイル内のすべての列をロードする必要はないため、以下ではインデックス 1、2、4、および 11 の列のみを読み取ることを選択します。また、ファイルにはヘッダーが含まれていないため、 、その後のアクセスをもう少し明確にするために、列の名前をより意味のある名前に変更します。
/**
* Loads UK house price from the Land Registry stored in an Amazon S3 bucket
* Note the data does not have a header, so columns will be named Column-0, Column-1 etc...
* @param year the year for which to load prices
* @return the resulting DataFrame, with some columns renamed
*/
private DataFrame < Integer , String > loadHousePrices ( Year year ) {
String resource = "http://prod.publicdata.landregistry.gov.uk.s3-website-eu-west-1.amazonaws.com/pp-%s.csv" ;
return DataFrame . read (). csv ( options -> {
options . setResource ( String . format ( resource , year . getValue ()));
options . setHeader ( false );
options . setCharset ( StandardCharsets . UTF_8 );
options . setIncludeColumnIndexes ( 1 , 2 , 4 , 11 );
options . getFormats (). setParser ( "TransactDate" , Parser . ofLocalDate ( "yyyy-MM-dd HH:mm" ));
options . setColumnNameMapping (( colName , colOrdinal ) -> {
switch ( colOrdinal ) {
case 0 : return "PricePaid" ;
case 1 : return "TransactDate" ;
case 2 : return "PropertyType" ;
case 3 : return "City" ;
default : return colName ;
}
});
});
}
以下では、英国の大都市の一部について、1995 年から 2014 年までの各年のアパートの名目価格の中央値 (インフレ調整なし) を計算するためにこのデータを使用します。 1993 年から 2014 年までのフィルターされていないデータセットには約 2,000 万件のレコードがあり、ロードと解析 (約 3.5 GB のデータ) にはかなりの時間がかかりますが、Morpheus はコードの分析部分を約 5 秒で実行します (データは含まれません)。 2013 年後半に購入した標準的な Apple Macbook Pro での読み込み時間)。 results.rows().keys().parallel()
。
//Create a data frame to capture the median prices of Apartments in the UK'a largest cities
DataFrame < Year , String > results = DataFrame . ofDoubles (
Range . of ( 1995 , 2015 ). map ( Year :: of ),
Array . of ( "LONDON" , "BIRMINGHAM" , "SHEFFIELD" , "LEEDS" , "LIVERPOOL" , "MANCHESTER" )
);
//Process yearly data in parallel to leverage all CPU cores
results . rows (). keys (). parallel (). forEach ( year -> {
System . out . printf ( "Loading UK house prices for %s... n " , year );
DataFrame < Integer , String > prices = loadHousePrices ( year );
prices . rows (). select ( row -> {
//Filter rows to include only apartments in the relevant cities
final String propType = row . getValue ( "PropertyType" );
final String city = row . getValue ( "City" );
final String cityUpperCase = city != null ? city . toUpperCase () : null ;
return propType != null && propType . equals ( "F" ) && results . cols (). contains ( cityUpperCase );
}). rows (). groupBy ( "City" ). forEach ( 0 , ( groupKey , group ) -> {
//Group row filtered frame so we can compute median prices in selected cities
final String city = groupKey . item ( 0 );
final double priceStat = group . colAt ( "PricePaid" ). stats (). median ();
results . data (). setDouble ( year , city , priceStat );
});
});
//Map row keys to LocalDates, and map values to be percentage changes from start date
final DataFrame < LocalDate , String > plotFrame = results . mapToDoubles ( v -> {
final double firstValue = v . col (). getDouble ( 0 );
final double currentValue = v . getDouble ();
return ( currentValue / firstValue - 1d ) * 100d ;
}). rows (). mapKeys ( row -> {
final Year year = row . key ();
return LocalDate . of ( year . getValue (), 12 , 31 );
});
//Create a plot, and display it
Chart . create (). withLinePlot ( plotFrame , chart -> {
chart . title (). withText ( "Median Nominal House Price Changes" );
chart . title (). withFont ( new Font ( "Arial" , Font . BOLD , 14 ));
chart . subtitle (). withText ( "Date Range: 1995 - 2014" );
chart . plot (). axes (). domain (). label (). withText ( "Year" );
chart . plot (). axes (). range ( 0 ). label (). withText ( "Percent Change from 1995" );
chart . plot (). axes (). range ( 0 ). format (). withPattern ( "0.##'%';-0.##'%'" );
chart . plot (). style ( "LONDON" ). withColor ( Color . BLACK );
chart . legend (). on (). bottom ();
chart . show ();
});
選択した都市のサブセットにおけるアパートの名目中央価格の変化率を以下のプロットに示します。これは、ロンドンが世界金融危機(GFC)の結果として名目住宅価格の下落に見舞われていないことを示していますが、英国のすべての都市が回復力があることが証明されたわけではありません。少し驚くべきことは、2003 年から 2006 年にかけて、裕福ではない北部の都市の一部ではロンドンに比べて上昇率が高かったことです。注意すべき点の 1 つは、ロンドンでは名目価格の引き下げは見られませんでしたが、世界金融危機中にポンドがこれらの通貨に対して大幅に下落したため、ユーロと米ドルに関してはかなり厳しい調整が確実にあったことです。
Morpheus DataFrames
でのデータの視覚化は、JFreeChart と Google Charts の両方をサポートするアダプターを備えたシンプルなチャート抽象化 APIによって簡単に実行できます (その他のアダプターも一般的な需要に応じて追随します)。この設計により、同じプログラム インターフェイスを介して、インタラクティブな Java Swing チャートと HTML5 ブラウザ ベースのチャートを生成することが可能になります。この API の使用方法の詳細については、ここの視覚化に関するセクションと、ここのコードを参照してください。
Morpheus は Maven Central に公開されているため、選択したビルド ツールに依存関係として簡単に追加できます。現在、コードベースは 5 つのリポジトリに分割されており、各モジュールを独立して進化させることができます。 morpheus-core という適切な名前が付けられたコア モジュールは、他のすべてのモジュールが依存する基本的なライブラリです。さまざまな Maven アーティファクトは次のとおりです。
モーフィアスコア
Morpheus 配列、DataFrame、その他の主要なインターフェイスと実装を含む基本ライブラリ。
< dependency >
< groupId >com.zavtech</ groupId >
< artifactId >morpheus-core</ artifactId >
< version >${VERSION}</ version >
</ dependency >
モーフィアスの視覚化
チャートやテーブルにDataFrames
表示するための視覚化コンポーネント。
< dependency >
< groupId >com.zavtech</ groupId >
< artifactId >morpheus-viz</ artifactId >
< version >${VERSION}</ version >
</ dependency >
モーフィアス・クワンドル
Quandl からデータをロードするアダプター
< dependency >
< groupId >com.zavtech</ groupId >
< artifactId >morpheus-quandl</ artifactId >
< version >${VERSION}</ version >
</ dependency >
モーフィアス・グーグル
Google Finance からデータをロードするアダプター
< dependency >
< groupId >com.zavtech</ groupId >
< artifactId >morpheus-google</ artifactId >
< version >${VERSION}</ version >
</ dependency >
モーフィアス・ヤフー
Yahoo Finance からデータをロードするアダプター
< dependency >
< groupId >com.zavtech</ groupId >
< artifactId >morpheus-yahoo</ artifactId >
< version >${VERSION}</ version >
</ dependency >
Google グループを使用して質問と回答のフォーラムが設定されており、ここからアクセスできます
Morpheus Javadoc には、ここからオンラインでアクセスできます。
ここから継続的インテグレーション ビルド サーバーにアクセスでき、各マージ後にコードをビルドします。
Morpheus は、Apache Software Foundation ライセンス バージョン 2 に基づいてリリースされています。