William Baum( 와이제이바움 ), 대학원 통계학과 학생, New Hampshire 대학교
제 프로젝트는 JMP 스크립팅 언어를 사용하여 여러 웹사이트에서 데이터를 가져와 프로 축구 승리를 예측하는 것입니다. 이 스크립트는 그렇지 않으면 힘들게 데이터를 수집, 집계, 재구성하여 분석하는 과정을 자동화합니다. 스크립트의 여러 섹션에는 셀 처리로 하위 스크립트를 제거하고 여러 데이터 세트를 연결하고 조인하는 것과 같은 다양한 기능이 포함되어 있습니다. 연관 배열을 사용하여 개별 행의 열 수식 출력을 비교합니다. 마지막으로 여러 예측 모델의 결과를 비교합니다. 이 프로젝트의 목적은 주로 JSL을 사용하여 데이터 수집, 구성 및 예측 프로세스를 반복 가능한 방식으로 자동화하는 방법을 설명하는 것입니다.
소개
약 2년 전, 저는 JMP가 JMP 스크립팅 언어[JSL]로 웹에서 데이터를 스크래핑할 수 있다는 것을 알게 되었습니다. 대학원 통계학 전공생으로서 저는 종종 분석 기술을 연마하고 코딩을 개선할 수 있는 연습 데이터를 찾고 있습니다. 저는 열렬한 미식축구 팬이고 스포츠 통계는 다양한 출처에서 온라인에서 쉽게 구할 수 있습니다. 연습으로, 저는 웹에서 스크래핑한 데이터로 각 프로 축구 팀의 시즌 총 승리를 예측해 보았습니다.
데이터 스크래핑 및 정리 기술은 웹에서 html 테이블 형태로 제공되는 모든 데이터에 적용할 수 있습니다. JSL을 사용하여 데이터 정리를 자동화하고 단일 스크립트 또는 스크립트의 복합 그룹 내에서 모델링을 수행할 수 있다는 사실이 놀랍습니다. 더욱이 JMP는 사용자가 그래픽 사용자 인터페이스[GUI]를 통해 분석을 수행하고 나중에 재사용 가능한 스크립트로 프로세스를 저장할 수 있도록 하여 프로그래밍 경험이 부족한 사용자에게 도움이 됩니다. 이를 통해 사용자는 업데이트되거나 새로운 데이터로 분석을 반복할 때 많은 시간을 절약할 수 있습니다.
설정
첫 번째 단계는 데이터 집계 과정에서 생성되는 파일을 저장할 폴더를 만드는 것이었습니다. 각 데이터 소스에 대한 폴더를 만드는 것이 생성된 많은 파일을 정리하는 데 효과적이라는 것을 알게 되었습니다.

다음으로, 더 깔끔한 코드를 만들기 위해 스크립트 사용자에게 파일 저장을 위한 로컬 경로를 지정하도록 요청했습니다. dir = Pick Directory(“파일 저장을 위한 디렉토리 선택”, show files(0));
이 로컬 경로는 하드코딩될 수도 있습니다.
경로가 선택되면, 데이터는 여러 웹사이트에서 스크래핑되어 개별 파일(HTML 테이블당 하나씩)에 저장되었습니다. 이러한 파일은 나중에 데이터 집계 단계에서 참조되었습니다.
데이터 스크래핑
JMP를 사용하면 브라우저의 주소창에서 URL 이름을 복사하여 JSL 코드에 붙여넣기만 하면 됩니다. 스크립트에 웹사이트 링크를 직접 넣을 수도 있는데, 이는 JSL 코드를 편집하는 동안 웹사이트를 여는 데 도움이 됩니다. Web("http://url_name.com");
데이터 가져오기
JMP에는 데이터 가져오기를 돕는 유용한 도구가 많이 있습니다. 첫째, html 테이블을 JMP 파일로 직접 저장해 볼 수 있습니다. 이 방법은 데이터를 거의 재구성할 필요가 없을 때 가장 효과적입니다. 두 번째 방법은 먼저 html 테이블을 쉼표로 구분된 값[CSV] 파일로 저장한 다음 JSL을 통해 사용할 수 있는 사용자 정의 설정으로 JMP로 가져오는 것입니다. 가져온 테이블을 살펴본 후 여러 개의 빈 열을 발견했습니다. "delete columns" 명령을 사용하여 짧은 스크립트로 테이블에서 빈 열을 삭제할 수 있었습니다.

JMP는 자동으로 웹에서 정보를 가져와 파일을 저장합니다. 반드시 이러한 파일을 저장할 필요는 없지만 웹에서 스크래핑한 데이터는 때때로 약간 지저분할 수 있습니다. 데이터를 파일에 저장하면 가져온 테이블을 보고 필요에 따라 코드를 조정할 수 있으므로 디버깅이 더 쉬워집니다.
방법 1
데이터는 CSV 파일로 가져와서 저장됩니다. 처음에는 다음과 같습니다.
ObjectName = Open(“http//:url_name1.com”, HTML Table(#))<< Set Name(“TableName1”) << Save(dir||“FileName1.csv”);
방법 2
데이터는 JMP로 직접 가져와서 저장됩니다.
ObjectName = Open(“http://url_name2.com”, HTML Table(#)<< Set Name(“TableName2”) << Save(dir||“FileName2.jmp”);

세포 처리
스크립트에서 문자 데이터를 정렬할 때 가져온 문자열에 약간의 변형만 있어도 코드가 엉망이 될 수 있습니다. 이 경우 플레이오프가 임박했고 New England가 디비전 타이틀을 차지했음을 나타내기 위해 이름에 "z"를 삽입했습니다. 다행히도 JMP는 셀 내의 문자열을 조작하는 다양한 명령을 제공합니다.

다음 스크립트에서 JMP는 "Team" 이름 열의 각 행을 반복하고 문자열의 시작 부분에 나타나는 경우 지정된 문자를 삭제합니다. "For Each Row" 명령은 각 행에 프로세스를 적용하는 간편한 반복을 제공합니다. 조건부 "if, then" 구문은 특정 조건이 적용될 때 JMP에 수행할 작업을 알려줍니다. "Contains" 명령은 문자열 내에서 지정된 항목의 위치를 반환합니다. "Substr"(substring) 명령은 문자열의 일부를 반환합니다. 지정된 위치에서 시작하여 지정된 수의 문자를 반환합니다.

테이블 결합
JMP에서 테이블을 결합하는 것은 "테이블" 메뉴를 통해 쉽습니다. 테이블 메뉴는 여러 옵션을 제공합니다. 일반적으로 "Join"을 사용하여 열은 다르지만 행 레이블은 같은 테이블을 결합합니다. 행 레이블은 다르지만 열은 같은 테이블을 결합할 때는 "Concatenate"를 사용합니다. 이 경우 여러 테이블의 정보를 연결했습니다. 각 팀 부서에 대해 하나의 테이블이 만들어졌습니다. 그런 다음 나중에 결합 프로세스 중에 같은 행이 일치하도록 하기 위해 결과 파일의 행을 팀 이름 순으로 알파벳순으로 정렬했습니다.

새 테이블 만들기
테이블을 조인하기 전에 새 테이블을 만드는 것이 유용하다는 것을 알았습니다. JMP를 사용하면 사용자가 여러 가지 방법으로 새 테이블을 만들 수 있습니다. 첫째, GUI를 통해 만들 수 있습니다. 스크립트를 통해서도 만들 수 있습니다. 이 경우 "새 테이블" 명령을 사용하여 각 축구 팀에 대해 하나씩 적절한 행 수의 새 테이블을 만들었습니다. 그런 다음 "새 열" 명령으로 팀 이름 열을 추가하고 목록으로 값을 설정했습니다.

테이블 조인
JMP 없이 테이블을 조인하는 것은 성가신 작업이라고 생각합니다. 다행히도 JMP는 "테이블" 메뉴에서 테이블을 조인하기 위한 멋진 GUI를 제공합니다. 명명 규칙은 항상 중요하지만, JMP는 동일한 이름을 공유하는 다른 테이블에서 유래한 열의 이름을 자동으로 바꿉니다. 이 경우 GUI를 통해 테이블을 조인한 다음 결과 테이블의 테이블 스크립트를 더 크고 사용자 정의 스크립트에 복사하여 붙여넣었습니다. 그렇지 않았다면 테이블을 조인하기 전에 많은 타이핑(열 이름 바꾸기)을 해야 했을 것입니다. 조인 프로세스를 여러 번 반복했습니다.

열 이름 바꾸기 및 다시 포맷하기
조인이 완료된 후, 이상하게 들리는 열 이름이 많이 생겼습니다. 혼란을 없애기 위해, 저는 그 열들의 이름을 바꾸었습니다. 그러기 위해, 저는 먼저 선호하는 이름 목록을 만들었습니다. 그런 다음, 루프와 "이름 설정" 기능을 조합하여 열의 이름을 바꾸었습니다.

때때로 JMP는 데이터를 문자열로 가져오지만, 사용자는 시간과 같은 다른 열 형식이 필요합니다. 이는 JMP GUI에서 쉽게 변경할 수 있지만 JSL 스크립트에서도 수행할 수 있습니다. 이 경우, JMP에 열에 문자 대신 연속 시간 정보가 포함되어 있음을 알렸습니다.
열 재정비
데이터가 집계되고 새로운 열이 생성되면 데이터 테이블의 열 순서를 변경하고 싶을 수 있습니다. JSL에서 "Move Selected Columns" 명령을 사용하면 쉽게 수행할 수 있습니다.

데이터 테이블 뷰
완성된 데이터 표의 일부 보기는 다음과 같습니다.

연관 배열 개발
데이터 집계를 마치고 나서는 분석을 할 차례였습니다. 제가 가장 먼저 비교하고 싶었던 것은 시즌의 그 시점까지 일정의 강도에 따라 다른 팀의 상대적 강점이었습니다. 제 목표는 팀의 미래 성과가 얼마나 강할지 예측하는 것이었는데, 이는 팀의 과거 성과뿐만 아니라 미래 상대의 과거 성과와도 관련이 있었습니다. 이를 위해 저는 제 테이블의 다른 행과 열에 있는 셀에 포함된 정보를 비교해야 했습니다. 연관 배열(일명 사전 또는 해시 맵)을 만드는 것이 이 작업에 매우 유용했습니다.
JMP에서는 연관 배열에서 목록, 행렬 또는 열을 사용할 수 있습니다. 이 경우 기본값(null)이 있는 두 개의 열을 사용했습니다. 키 열 "TEAM"에는 각 팀의 약어 도시 이름이 포함되었습니다. "Strength"라는 값 열은 승리 및 순점을 결합한 인덱스를 계산하는 수식 열이었습니다. 17주 경기 일정의 각 주(열)를 키로 사용하여 해당 주의 연관 배열 값을 참조했습니다.
17주 일정: 키

스크립트에서 연관 배열을 정의한 다음, 이를 참조할 수식 열을 만들었습니다. 다시 말해서, 수식은 연관 배열의 서브스크립트를 통해 올바른 값을 참조하며, 주간 상대를 키로 사용합니다. 키 열의 값이 연관 배열에 없으면 함수는 null 값을 반환합니다(일정에서 bye 주와 잘 작동합니다).

그런 다음 각 주에 대해 새로운 열을 만들어 팀 강점을 비교했습니다. 이 두 공식은 합쳐질 수도 있었지만, 데이터 테이블에서 다른 지표를 시각화할 수 있도록 분리해 두는 것을 선호했습니다.

다음으로, 저는 시즌의 예상 승리 수를 세었습니다. 열 결과를 세는 간단한 방법은 17개 열 각각에 대한 일련의 "If-Then" 조건의 합을 포함하는 새로운 공식 열을 만드는 것이었습니다. 이 경우, Strength의 차이가 양수이면 예측은 승리로 간주되어 계산되었습니다.

예측 모델 생성
JMP에는 예측을 위한 다양한 모델링 기술이 있습니다. "Fit Model" 및 "Neural" 플랫폼을 포함하여 많은 기술은 "Analyze" 메뉴를 통해 액세스할 수 있습니다. 사용자 정의 스크립트를 만들 때는 먼저 JMP 플랫폼에서 최적의 모델을 개발하는 것이 좋습니다. 그런 다음 모델 스크립트를 데이터 테이블에 저장하고(GUI를 통해) 코드를 사용자 정의 스크립트에 복사하여 붙여넣을 수 있습니다. JSL을 사용하여 모델 스크립트를 데이터 테이블에 저장할 수도 있습니다. 이를 통해 사용자는 모델이 자동으로 실행되도록 설정하거나 사용자 정의 스크립트에서 만든 테이블의 데이터 테이블 스크립트 목록에서 모델을 사용할 수 있도록 할 수 있는 유연성을 얻습니다.
여기에 한 가지 예가 있습니다.

JMP Pro의 고급 모델링 기술
JMP Pro에서는 JMP 표준 버전에서는 사용할 수 없는 여러 가지 고급 모델링 기법을 사용할 수 있습니다. 두 가지 예로는 신경망의 부스트 버전과 탄력적 네트 일반화 회귀 기법이 있습니다. JMP의 또 다른 좋은 점은 사용자가 지정한 비율로 홀드백 검증을 수행하고 데이터 세트에서 무작위 샘플을 자동으로 선택하는 기능입니다. 이를 통해 검증과 모델 비교가 모두 용이해집니다.
부스트된 신경망

탄력있는 그물

때로는 여러 모델 예측의 평균이 개별 모델 성능보다 더 좋은 성과를 낼 수 있습니다.
여기서는 JSL로 두 개의 예측 수식의 평균을 계산하는 수식 열을 만들었습니다.

JMP Pro에는 사용자가 여러 모델의 상대적 효과를 나란히 비교할 수 있는 모델 비교 플랫폼이 있습니다. 모델 비교 플랫폼은 또한 사용자에게 몇 번의 클릭만으로 여러 모델을 평균화할 수 있는 기능을 제공합니다.
모델 비교

이 경우, Neural Net과 Elastic Net 모델의 평균(홀드백 검증[HB] 포함)은 두 개별 모델 중 어느 것보다 약간 더 나은 성과를 보였습니다. 모델 비교 플랫폼의 또 다른 좋은 기능은 "실제 대 예측" 및 "잔차 대 행" 플롯입니다.
모델 비교 플롯

결론
JMP 스크립팅 언어[JSL]를 사용하면 JMP는 여러 웹 소스에서 데이터를 스크래핑하고, 데이터를 처리하고, 여러 예측을 수행하고, 이를 비교하고, 이를 단일 스크립트 내에서 모두 표시할 수 있습니다. JSL을 효과적으로 사용하면 많은 시간을 절약할 수 있으며, 특히 정기적으로 분석을 반복해야 하는 경우에 그렇습니다.