Morpheus 라이브러리는 JVM(Java Virtual Machine)에서 오프라인 및 실시간 분석을 위한 대규모 데이터 세트가 포함된 고성능 분석 소프트웨어의 개발을 촉진하도록 설계되었습니다. 라이브러리는 람다를 광범위하게 사용하여 Java 8로 작성되었지만 모든 JVM 언어에서 액세스할 수 있습니다.
예제가 포함된 자세한 문서는 여기를 참조하세요.
기본적으로 Morpheus는 R에서 처음 대중화된 것과 유사한 DataFrame
이라는 다용도의 2차원 메모리 효율적인 표 형식 데이터 구조를 제공합니다. R, Python 및 Matlab과 같은 동적으로 유형이 지정된 과학 컴퓨팅 언어는 연구 수행에 적합하지만 적합하지는 않습니다. 유지 관리가 매우 어렵고 리팩터링이 위험하므로 대규모 생산 시스템에 적합합니다. Morpheus 라이브러리는 DataFrame
개념의 강력함과 다양성을 유지하는 동시에 훨씬 더 유형이 안전 하고 자체 설명되는 인터페이스 세트를 제공하여 코드 복잡성을 훨씬 쉽게 개발, 유지 관리 및 확장할 수 있도록 시도합니다.
Morpheus 라이브러리의 또 다른 장점은 Java Virtual Machine의 강력한 스레딩 기능을 통해 멀티 코어 프로세서 아키텍처 확장 에 매우 뛰어나다는 것입니다. 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, The Federal Reserve, The World Bank, 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" );
});
이 예는 많은 메소드 반환 유형이 실제로 DataFrame
이므로 이러한 형태의 메소드 체이닝을 허용하는 Morpheus API의 기능적 특성을 보여줍니다. 이 예에서 csv()
, select()
, add()
및 sort()
메서드는 모두 프레임을 반환합니다. 어떤 경우에는 메서드가 작동하는 것과 동일한 프레임이고, 다른 경우에는 작동 중인 프레임의 필터 또는 얕은 복사본입니다. 이 예에서 변환된 데이터세트의 처음 10개 행은 다음과 같으며 새로 추가된 열은 프레임의 맨 오른쪽에 나타납니다.
색인 | 제조업체 | 모델 | 유형 | 최소 가격 | 가격 | 최대 가격 | MPG.시티 | MPG.고속도로 | 에어백 | 드라이브트레인 | 실린더 | 엔진 크기 | 마력 | RPM | 마일당 회전수 | Man.trans.avail | 연료.탱크.용량 | 승객 | 길이 | 휠베이스 | 폭 | 턴서클 | 후방.좌석.룸 | 수하물.룸 | 무게 | 원산지 | 만들기 | 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 | 미국 | 올즈모빌 88 | 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 에서 마력을 회귀합니다. 코드 예제에서는 모델 결과를 아래 표시된 표준 출력으로 인쇄한 다음 회귀선이 명확하게 표시된 분산형 차트를 만듭니다.
//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 R-제곱: 0.5360 관측치: 93 R-제곱(조정): 0.5309 DF 모델: 1 F-통계: 105.1204 DF 잔차: 91 F-통계(Prob): 1.11E-16 표준 오류: 35.8717 런타임(밀리초) 52 더빈-왓슨: 1.9591 ================================================= ============================================ 색인 | 매개변수 | STD_ERROR | 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 형식으로 표시되며 거래 날짜, 지불 가격, 정규화된 주소(우편번호 포함), 부동산 유형, 임대 유형 등과 같은 정보를 포함하는 수많은 열을 포함합니다.
Amazon S3 버킷에서 이러한 CSV 파일을 로드하는 함수를 작성하는 것부터 시작하겠습니다. 이 파일은 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천만 개의 레코드가 있으며 로드 및 구문 분석에 상당히 오랜 시간이 걸리는 반면(약 3.5GB의 데이터) 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년 기간 동안 덜 부유한 북부 도시 중 일부가 런던에 비해 더 높은 평가율을 보였다는 것입니다. 한 가지 주목해야 할 점은 런던에서는 명목상 가격 하락이 없었지만 GFC 동안 파운드화의 가치가 크게 하락했기 때문에 EUR 및 USD 측면에서 상당히 심각한 조정이 있었다는 것입니다.
Morpheus DataFrames
의 데이터 시각화는 JFreeChart와 Google Charts(다른 사람들의 요구에 따라 다름)를 모두 지원하는 어댑터가 있는 간단한 차트 추상화 API 를 통해 쉽게 이루어집니다. 이 설계를 통해 동일한 프로그래밍 인터페이스를 통해 대화형 Java 스윙 차트는 물론 HTML5 브라우저 기반 차트를 생성할 수 있습니다. 이 API를 사용하는 방법에 대한 자세한 내용은 여기의 시각화 섹션과 여기의 코드를 참조하세요.
Morpheus는 Maven Central에 게시되므로 선택한 빌드 도구에 종속성으로 쉽게 추가할 수 있습니다. 코드베이스는 현재 5개의 저장소로 나누어져 있어 각 모듈을 독립적으로 발전시킬 수 있습니다. morpheus-core라는 적절한 이름의 코어 모듈은 다른 모든 모듈이 의존하는 기본 라이브러리입니다. 다양한 Maven 아티팩트는 다음과 같습니다.
모피어스 코어
Morpheus Arrays, DataFrames 및 기타 주요 인터페이스 및 구현을 포함하는 기본 라이브러리입니다.
< 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 Javadocs는 여기에서 온라인으로 액세스할 수 있습니다.
각 병합 후에 코드를 빌드하는 지속적인 통합 빌드 서버에 여기에서 액세스할 수 있습니다.
Morpheus는 Apache Software Foundation 라이선스 버전 2에 따라 출시됩니다.