Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별추가 기능이 Mac에서 작동한다는 소식을 듣고 기쁩니다.
당신 말이 맞아요, 추가 기능을 가능한 한 일반적으로 만든 후에 "sprint"에 대한 필터를 다시 추가하는 것을 잊었습니다.
다음 코드:
- 추가 기능을 사용하여 Strava에서 최신 데이터 가져오기
- "sprint" 이름만 포함하도록 행을 필터링합니다.
- "2022_03_28 Strava Sprinting Training Data Set 5 Runs" 데이터 세트에 게시된 내용과 일치하도록 열을 필터링합니다.
- 모티프 식별
- 데이터 테이블에 스크립트를 추가하여 결과를 차트로 표시
names default to here(1);
// if add-in is found, get fresh data from Strava, otherwise just use current data table
if( file exists("$ADDIN_HOME(com.caes.ngambles.strava-get-activities)\main.jsl"),
include("$ADDIN_HOME(com.caes.ngambles.strava-get-activities)\main.jsl");
wait(0);
);
// get reference to current data table
dt = current data table();
// Clean up data set for specific motif extraction challenge
if( contains( dt << get column names(string), "name"),
r = dt << get rows where(
!contains(lower case(:name), "sprint")
);
try(dt << delete rows(r));
);
colList = {
"name",
"altitude",
"distance",
"grade_smooth",
"lat",
"lng"
};
for( k = 1, k <= n items(colList), k++,
try(dt << delete column( colList(k) ));
);
// Find Regions that match target shapes
dt << New Column( "Shape Match",
Numeric,
nominal,
Formula(
thresh = 12500;
shapeList = {
{221, 245, 289, 327, 374, 431, 477, 518, 535, 518, 491, 451, 401, 350, 304, 238, 178, 161, 156, 106, 96, 96, 87, 85, 81, 79, 76, 74, 73, 72, 73, 72, 72, 72, 72, 72, 71, 70, 70, 70},
{306, 321, 347, 384, 429, 476, 515, 546, 579, 582, 576, 542, 489, 442, 375, 348, 295, 275, 242, 185, 152, 121, 106, 98, 93, 89, 89, 85, 84, 83, 82, 82, 81, 80, 79, 79, 78, 78, 78, 78},
{357, 390, 401, 428, 475, 505, 558, 604, 619, 634, 634, 625, 581, 530, 483, 444, 378, 357, 324, 282, 214, 186, 162, 153, 137, 132, 124, 109, 104, 97, 94, 90, 90, 89, 88, 87, 87, 85, 85, 86}
};
minErr = Empty();
For( k = 1, k <= N Items( shapeList ), k++,
err = 0;
For( n = 0, n < N Items( shapeList[k] ), n++,
For( m = 1, m <= N Items( shapeList[k] ), m++,
err += (:watts[(Row() + m) - n - 1] - shapeList[k][m]) ^ 2
);
err /= N Items( shapeList[k] ) - 1;
minErr = Minimum( minErr, err );
);
);
If( minErr <= thresh,
flag = 1,
flag = 0
);
flag;
)
);
// Run Region
dt << New Column( "Run Region",
Numeric,
"Continuous",
Formula(
regionCount = Summation( k = 0, 5, Lag( :Shape Match, k ) );
If( regionCount < 6 & region Count > 0 & :Shape Match == 1,
nearStart = 1,
nearStart = 0
);
If( nearStart == 0,
ans = :Shape Match;
,
ans = 0;
If( :watts[row()] > 0 & :watts[row() +1] > 0,
ans = :Shape Match;
)
);
ans;
)
);
// motif ID
dt << New Column( "Motif ID",
Numeric,
Nominal,
Formula(
mID = 0;
For( k = 1, k <= Row(), k++,
If( :Run Region[k - 1] == 0 & :Run Region[k] == 1,
mID++
)
);
If( :Run Region == 1, mID );
)
);
// row state formula column
dt << New Column("Row State Formula",
Row State,
Row State,
Formula(
If(
Is Missing(:Motif ID),
Row State() = Combine States(Hidden State(1), Excluded State(1)),
Row State()
)
)
);
// linear interpolation of zero values within motif ID
dt << New Column( "watts modified",
Numeric,
Continuous,
Formula(
If( Is Missing( :Motif ID ),
Empty(),
If( :watts > 0,
:watts,
rb = Row();
ra = Row();
For( k = Row(), k >= 1, k--,
If( :watts[k] != 0,
rb = k;
Break();
)
);
For( k = Row(), k <= N Rows(), k++,
If( :watts[k] != 0,
ra = k;
Break();
)
);
deltaPower = :watts[rb] - :watts[ra];
deltaTime = rb - ra;
:watts[rb] + (deltaPower / deltaTime) * (Row() - rb);
)
)
)
);
// rank timestamp, Motif ID - x axis values to help graph each motif
dt << New Column( "X",
Numeric,
Continuous,
Formula( Col Rank( :timestamp, :Motif ID ) )
);
// graph results script added to data table
dt << new script(
"Graph Results",
names default to here(1);
dt = current data table();
nw = new window(
"Motif Extraction Results",
h list box(
gb1 = dt << Graph Builder(
Show Control Panel( 0 ),
Show Legend( 0 ),
Show Footer( 0 ),
Variables(
X( :Name( "X" ) ),
Y( :watts modified ),
Wrap( :Motif ID )
),
Elements( Line( X, Y, Legend( 6 ) ), Points( X, Y, Legend( 7 ) ) )
)
,
gb2 = dt << Graph Builder(
Show Control Panel( 0 ),
Show Footer( 0 ),
Variables( X( :X ), Y( :watts modified ), Overlay( :Motif ID ) ),
Elements(
Smoother( X, Y, Legend( 5 ), Lambda( 0.0014 ) ),
Points( X, Y, Legend( 6 ) )
)
)
)
);
);
// run script to make graphs
// eval( dt << get property("Graph Results") );Re: JMP 작업 흐름 과제 1: 연속 전력 데이터에서 모티프 추출 및 식별Mac에서는 작동하지만 새로 고침 토큰을 잘못 입력하면 추가 기능이 로드되지 않으므로 제거하고 다시 설치해야 합니다. 이것이 모든 최근 활동을 가져오고 있습니까? 관심 있는 제목(예: "sprint")이 있는 항목만 가져오는 검색 문자열이 있는 것이 좋을 수 있습니다.
Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별Mac에서는 테스트할 수 없으므로 기본 선택은 Windows 전용이었습니다.Windows와 Mac을 모두 허용하는 추가 기능이 첨부되어 있습니다. 작동하지 않아야 하는 이유를 모르겠지만 테스트되지 않았습니다.
Mac에서 성공적으로 실행되는지 알려주세요.
Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별이것이 macOS에서 작동하지 않는 이유가 있습니까? 방금 로드하려고 했는데 Windows용으로만 만들었을 수 있습니다.
Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별나는 이 도전에 대한 초기 접근법에 대해 생각하고 있었고 더 잘할 수 있다고 생각하여 두 번째 시도를 했습니다.
이번에는 여러 대상 모양을 정의한 다음 모양이 합리적으로 잘 일치하는 영역을 찾기 위해 데이터를 검색합니다. 내가 정의한 대상 모양은 다음과 같습니다.

이 방법은 더 적은 조정 매개변수가 필요하며 추가 대상 모양을 쉽게 추가할 수 있도록 하여 더 많은 유연성을 허용합니다.
실행 중에 와트 값이 떨어질 때 선형 외삽을 수행하는 열(와트 수정됨)을 추가했습니다.
모티프 ID와 연결되지 않은 데이터 포인트를 자동으로 숨기고 제외하는 열(행 상태 수식)도 추가했습니다.
내 생각에 이것은 도전에 대한 나의 초기 솔루션보다 개선된 것입니다.
이 방법은 "2022_03_28 Strava Sprinting Training Data Set 5 Runs.jmp" 데이터 세트에서 41개의 런을 식별합니다.

Strava 데이터를 처리하는 JSL 코드는 다음과 같습니다.
names default to here(1);
<BR />// uncomment the following two lines if you have installed the Strava - Get Activities add-in and want to automatically download the Strava data prior to identifying motifs<BR />// include("$ADDIN_HOME(com.caes.ngambles.strava-get-activities)\main.jsl");<BR />// wait(0);<BR />
dt = current data table();
// Find Regions that match target shapes
dt << New Column( "Shape Match",
Numeric,
nominal,
Formula(
thresh = 12500;
shapeList = {{221, 245, 289, 327, 374, 431, 477, 518, 535, 518, 491, 451, 401, 350, 304, 238, 178, 161, 156, 106, 96, 96, 87, 85, 81, 79, 76,
74, 73, 72, 73, 72, 72, 72, 72, 72, 71, 70, 70, 70}, {306, 321, 347, 384, 429, 476, 515, 546, 579, 582, 576, 542, 489, 442, 375, 348, 295,
275, 242, 185, 152, 121, 106, 98, 93, 89, 89, 85, 84, 83, 82, 82, 81, 80, 79, 79, 78, 78, 78, 78}, {357, 390, 401, 428, 475, 505, 558, 604,
619, 634, 634, 625, 581, 530, 483, 444, 378, 357, 324, 282, 214, 186, 162, 153, 137, 132, 124, 109, 104, 97, 94, 90, 90, 89, 88, 87, 87, 85,
85, 86}};
minErr = Empty();
For( k = 1, k <= N Items( shapeList ), k++,
err = 0;
For( n = 0, n < N Items( shapeList[k] ), n++,
For( m = 1, m <= N Items( shapeList[k] ), m++,
err += (:watts[(Row() + m) - n - 1] - shapeList[k][m]) ^ 2
);
err /= N Items( shapeList[k] ) - 1;
minErr = Minimum( minErr, err );
);
);
If( minErr <= thresh,
flag = 1,
flag = 0
);
)
);
// Run Region - helps clean up regions found by shape match
dt << New Column( "Run Region",
Numeric,
"Continuous",
Formula(
regionCount = Summation( k = 0, 5, Lag( :Shape Match, k ) );
If( regionCount < 6 & region Count > 0 & :Shape Match == 1,
nearStart = 1,
nearStart = 0
);
If( nearStart == 0,
ans = :Shape Match;
,
ans = 0;
If( :watts[row()] > 0 & :watts[row() +1] > 0,
ans = :Shape Match;
)
);
ans;
)
);
// motif ID
dt << New Column( "Motif ID",
Numeric,
Nominal,
Formula(
mID = 0;
For( k = 1, k <= Row(), k++,
If( :Run Region[k - 1] == 0 & :Run Region[k] == 1,
mID++
)
);
If( :Run Region == 1, mID );
)
);
// row state formula column
dt << New Column("Row State Formula",
Row State,
Row State,
Formula(
If(
Is Missing(:Motif ID),
Row State() = Combine States(Hidden State(1), Excluded State(1)),
Row State()
)
)
);
// linear interpolation of zero values within motif ID
dt << New Column( "watts modified",
Numeric,
Continuous,
Formula(
If( Is Missing( :Motif ID ),
Empty(),
If( :watts > 0,
:watts,
rb = Row();
ra = Row();
For( k = Row(), k >= 1, k--,
If( :watts[k] != 0,
rb = k;
Break();
)
);
For( k = Row(), k <= N Rows(), k++,
If( :watts[k] != 0,
ra = k;
Break();
)
);
deltaPower = :watts[rb] - :watts[ra];
deltaTime = rb - ra;
:watts[rb] + (deltaPower / deltaTime) * (Row() - rb);
)
)
)
);
// rank timestamp, Motif ID - x axis values to help graph each motif
dt << New Column( "X",
Numeric,
Continuous,
Formula( Col Rank( :timestamp, :Motif ID ) )
);
Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별API를 통해 와트가 들어오게 되어 기쁩니다.
새로 고쳐진 액세스 코드를 자동으로 가져오는 것을 처리하는 Strava API 코드를 몇 가지 더 업데이트한 다음 첨부한 일반 추가 기능으로 롤업했습니다.
애드인을 처음 실행하면 Strava API 정보를 입력하라는 메시지가 표시됩니다.

추가 기능 폴더에 저장되므로 다시 입력할 필요가 없습니다.
추가 기능은 Strava에서 사용 가능한 모든 활동이 포함된 데이터 테이블을 반환합니다.

이 추가 기능은 이 프로젝트뿐만 아니라 Strava에서 데이터를 탐색하려는 다른 사용자를 위해 Strava API에서 데이터를 가져오는 프로세스를 더욱 간소화합니다.
Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별환상적인 @ngambles . 이것은 훌륭하게 작동하며 액세스 토큰을 얻는 방법을 설명하는 비디오 링크를 게시해 주셔서 감사합니다. 이 데이터는 내가 보고 싶을 때 들어오는 것입니다. 또한 이것은 수동으로 내보내고 .csv 파일에 결합하는 것보다 훨씬 개선되었습니다. 이 데이터 가져오기를 자동화하고 데이터를 정리하여 정기적으로 분석하고 JMP Live에 게시할 수 있는 단계를 실제로 설정합니다. 네, 스크립트에서 API를 통해 와트가 들어오고 있습니다.

나는 붙여넣었다 @brady_brady 위에서 의 수식을 사용했지만 여전히 모든 간격을 얻지는 못했습니다. 그러나 덕분에 @ngambles 의 Strava API 코드를 사용하면 탐색하고 사용할 데이터 세트에 또 다른 흥미로운 기능이 있는데, 바로 매끄러운 속도 열입니다. 이것이 유용할 수 있다고 생각합니다. 또한 이제 다른 기능으로 작업할 수 있는 고유한 활동 ID가 있습니다. ML 모델을 다시 던져야 한다고 생각합니다. @Byron_JMP , 이제 더 큰 훈련 데이터 세트와 모델을 구축하기 위한 몇 가지 추가 기능이 있습니다.
업데이트된 학습 데이터 세트를 첨부했습니다.

그리고 @Jordan_Hiller 당신도 시도해야한다고 생각합니다! 당신은 데이터 정리 전문가입니다.
Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별Strava API에서 직접 데이터를 가져오는 방법을 시도했습니다.거리, 속도, 위치, 고도 및 등급에 대한 측정값을 성공적으로 얻고 있습니다. 그러나 나는 전력 측정을 얻지 못하고 있습니다.내 Strava 계정 수준 및/또는 전력 측정 장비 부족 때문이 아닐까 의심됩니다. 내 코드가 Strava 데이터에 전력 데이터가 있는 사용자에게 적합할 수 있다고 믿을만한 이유가 있지만 확인할 수는 없습니다. 이 솔루션이 올바르지 않으면 필요한 것과 너무 멀리 떨어져 있다고 상상할 수 없습니다.
나는 이것을 찾았다 유튜브 비디오 Strava API를 시작하는 데 매우 유익합니다. JSL 코드가 Strava에서 정보를 가져오기 전에 필요한 Strava API에서 액세스 토큰을 가져오는 방법을 명확하게 보여줍니다. 아래 코드에서 your_access_token_here를 실행하기 전에 Strava API에서 얻은 액세스 토큰으로 바꿉니다.
names default to here(1);
accessToken = "your_access_token_here"; // access token from the Strava API
// helpful link to get started with the API: https://www.youtube.com/watch?v=sgscChKfGyg
//////////////////////////////////////////
//////////////////////////////////////////
// get list of activities from Strava
s = New HTTP Request(
URL( "https://www.strava.com/api/v3/athlete/activities?access_token=" || accessToken ),
Method( "GET" ),
Headers( {"Accept: application/json"} )
) << Send;
dtx = json to data table(s);
dtx << set name("Activities List");
// keep only activites marked as sprint
r = dtx << get rows where(
!contains(lowercase(:name), "sprint")
);
dtx << delete rows(r);
if( n rows(dtx) == 0,
close(dtx, no save);
throw();
);
// get list of unique activity ids
summarize( activityList = by(dtx:id));
// get and combine the data from each activity
dty = new table();
dty << set name("Strava Data_temp");
for( k = 1, k <= n items(activityList), k++,
actStream = New HTTP Request(
URL( "https://www.strava.com/api/v3/activities/" || activityList[k] || "/streams?keys=latlng,watts,distance,velocity,altitude,velocity_smooth,cadence,temp,moving,grade_smooth&access_token=" || accessToken ),
Method( "GET" ),
Headers( {"Accept: application/json"} )
) << Send;
dtz = json to data table(actStream);
dtz << new column("Activity ID", numeric, nominal, set each value(num(activityList[k])));
dty << concatenate(dtz, append to first table);
close(dtz, no save);
);
// add rank column for x value
dty << New Column( "x",
Numeric,
"Continuous",
Formula( Col Rank( :Activity ID, :type, :Activity ID ) )
);
// split up latitude and longitude pairs
myCount = 0;
for( k = 1, k <= n rows(dty), k++,
if( dty:type[k] != "latlng",
dty:type[k] = dty:type[k]
,
myCount ++;
if( modulo(myCount,2) == 0,
dty:type[k] = "lat",
dty:type[k] = "lng"
)
);
);
// split tall table to wider table
dt = dty << Split(
Split By( :type ),
Split( :data ),
Group( :x, :Activity ID ),
Remaining Columns( Drop All ),
Sort by Column Property
);
// done with this data table
close(dty, no save);
// update start time from activities table
dt << Update(
With( dtx ),
Match Columns( :Activity ID = :id ),
Add Columns from Update Table( :start_date, :name ),
Replace Columns in Main Table( :start_date, :name )
);
// close activity list
close(dtx, no save);
// clean up time stamp
dt << Begin Data Update;
dt << Recode Column(
dt:start_date,
{Regex( _rcNow, ".*^(.*)Z.*", "\1", GLOBALREPLACE )},
Target Column( :start_date )
);
dt << End Data Update;
dt:start_date << data type(numeric) << Format( "yyyy-mm-ddThh:mm:ss", 19, 0 ) << Input Format( "yyyy-mm-ddThh:mm:ss", 0 );
dt << New Column( "timestamp",
Numeric,
"Continuous",
Format( "yyyy-mm-ddThh:mm:ss", 19, 0 ),
Input Format( "yyyy-mm-ddThh:mm:ss", 0 ),
Formula( (:start_date + :x) - 1 )
);
wait(0);
dt:timestamp << delete formula;
dt << delete column("start_date");
// arrange columns
dt << Move Selected Columns( {:timestamp}, To first );
dt << Move Selected Columns( {:Activity ID, :name}, after(:timestamp) );
// set name
dt << set name("Strava Data");
// sort chronologically
dt << Sort( By( :timestamp ), Order( Ascending ), replace table );
dt << sort( by(:Activity ID), order( ascending ), replace table );코드:
- 모든 Strava 활동을 살펴보고 이름에 "sprint"가 있는 활동만 선택합니다(대소문자 구분 안 함).
- 전력(와트)을 포함한 많은 측정값을 얻으려고 합니다.
- 이 챌린지에서 제공된 원본 데이터 세트와 유사한 데이터 테이블에 정보를 구성합니다.
Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별Strava API에서 바로 데이터를 가져오는 장면을 촬영했습니다. 거리, 속도, 경도, 위도, 고도 및 등급을 포함한 여러 측정값을 성공적으로 얻고 있습니다. 그러나 나는 힘을 얻지 못하고 있습니다. Strava 계정 및/또는 파워 측정 장비가 부족하기 때문일 수 있습니다. 이 솔루션은 Strava 계정에 전력 정보가 있는 사람에게 필요할 수도 있고 아닐 수도 있지만 정확하지 않다면 내가 너무 멀리 떨어져 있다고 상상할 수 없습니다.
Strava API를 시작하려면 이 유튜브 비디오는 매우 유용했으며 이 코드가 Strava에서 데이터를 가져오기 전에 필요한 액세스 토큰을 얻는 단계를 명확하게 보여줍니다. 아래 코드에서 your_access_token_here를 실제 액세스 토큰으로 바꾸십시오.
names default to here(1);
accessToken = "your_access_token_here"; // access token from the Strava API
// helpful link to get started with the API: https://www.youtube.com/watch?v=sgscChKfGyg
//////////////////////////////////////////
//////////////////////////////////////////
// get list of activities from Strava
s = New HTTP Request(
URL( "https://www.strava.com/api/v3/athlete/activities?access_token=" || accessToken ),
Method( "GET" ),
Headers( {"Accept: application/json"} )
) << Send;
dtx = json to data table(s);
dtx << set name("Activities List");
// keep only activities marked as sprint
r = dtx << get rows where(
!contains(lowercase(:name), "sprint")
);
dtx << delete rows(r);
if( n rows(dtx) == 0,
close(dtx, no save);
throw();
);
// get list of unique activity ids
summarize( activityList = by(dtx:id));
// get and combine the data streams from each activity
dty = new table();
dty << set name("Strava Data_temp");
for( k = 1, k <= n items(activityList), k++,
actStream = New HTTP Request(
URL( "https://www.strava.com/api/v3/activities/" || activityList[k] || "/streams?keys=latlng,watts,distance,velocity,altitude,velocity_smooth,cadence,temp,moving,grade_smooth&access_token=" || accessToken ),
Method( "GET" ),
Headers( {"Accept: application/json"} )
) << Send;
dtz = json to data table(actStream);
dtz << new column("Activity ID", numeric, nominal, set each value(num(activityList[k])));
dty << concatenate(dtz, append to first table);
close(dtz, no save);
);
// add rank column for x value
dty << New Column( "x",
Numeric,
"Continuous",
Formula( Col Rank( :Activity ID, :type, :Activity ID ) )
);
// split up latitude and longitude pairs
myCount = 0;
for( k = 1, k <= n rows(dty), k++,
if( dty:type[k] != "latlng",
dty:type[k] = dty:type[k]
,
myCount ++;
if( modulo(myCount,2) == 0,
dty:type[k] = "lat",
dty:type[k] = "lng"
)
);
);
// split tall table to wider table
dt = dty << Split(
Split By( :type ),
Split( :data ),
Group( :x, :Activity ID ),
Remaining Columns( Drop All ),
Sort by Column Property
);
// done with this data table
close(dty, no save);
// update start time from activities table
dt << Update(
With( dtx ),
Match Columns( :Activity ID = :id ),
Add Columns from Update Table( :start_date, :name ),
Replace Columns in Main Table( :start_date, :name )
);
// close activity list
close(dtx, no save);
// clean up time stamp
dt << Begin Data Update;
dt << Recode Column(
dt:start_date,
{Regex( _rcNow, ".*^(.*)Z.*", "\1", GLOBALREPLACE )},
Target Column( :start_date )
);
dt << End Data Update;
dt:start_date << data type(numeric) << Format( "yyyy-mm-ddThh:mm:ss", 19, 0 ) << Input Format( "yyyy-mm-ddThh:mm:ss", 0 );
dt << New Column( "timestamp",
Numeric,
"Continuous",
Format( "yyyy-mm-ddThh:mm:ss", 19, 0 ),
Input Format( "yyyy-mm-ddThh:mm:ss", 0 ),
Formula( (:start_date + :x) - 1 )
);
wait(0);
dt:timestamp << delete formula;
dt << delete column("start_date");
// arrange columns
dt << Move Selected Columns( {:timestamp}, To first );
dt << Move Selected Columns( {:Activity ID, :name}, after(:timestamp) );
// set name
dt << set name("Strava Data");
// sort chronologically
dt << Sort( By( :timestamp ), Order( Ascending ), replace table );
dt << sort( by(:Activity ID), order( ascending ), replace table );
코드:
- 대소문자를 구분하지 않고 이름에 "sprint"가 포함된 활동에 대한 데이터만 포함합니다.
- 거리, 속도, 위치, 고도 등을 포함한 많은 다른 측정 중에서 전력(와트)을 얻으려고 시도합니다.
- 이 과제에 제시된 원래 데이터 테이블과 유사한 형식으로 데이터를 정렬합니다.
Strava 계정에 전원 정보가 있는 사용자에게 이 코드가 작동하기를 바랍니다.
Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별좋아, 브래디.
인터벌 시작부터 중단까지 꽤 짧은 시간에 대한 좋은 지적입니다. 그러나 드롭아웃은 최대 2-3초인 것 같습니다. 이번 주에 수집되는 새로운 데이터를 통해 이것이 어떻게 유지되는지 살펴보겠습니다.
몇 가지 추가 교육 데이터가 첨부되어 있습니다. 이것은 매우 안정적인 상태 실행의 약 1:40이지만 더 많은 속도로 실행됩니다(내 임계 전력의 거의 100%). 도움이 될 수 있습니다 @Byron_JMP , 그러나 그의 ML 모델로. 워밍업/웜다운 범위에 더 가깝게 만들기 위해 이 훈련 데이터 세트에 기능을 추가할 수 있습니까?
또한 HTTP 요청()을 사용하여 Strava API를 통해 직접 데이터를 가져오려는 사람; JMP에서? 알아요 @dieter_pisot 이전에 이 작업을 수행했습니다. API를 통해 데이터 풀을 쉽게 검색할 수 있도록 스프린트와 같은 것으로 운동에 태그를 지정할 수 있습니다.

Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별다음은 (상대적으로 간단한) 수식 열을 사용하여 드롭아웃을 보간하는 또 다른 접근 방식입니다. 이 중 많은 수는 문제 해결과 수식 작성이 쉽지 않은 대신 더 복잡한 보간 수식을 사용하여 제거할 수 있습니다. (공식 및 그래프 스크립트는 첨부된 표 참조)
결과는 적어도 샘플 데이터 세트에서 우리가 원하는 것과 일치하는 것 같습니다. (빨간색 점은 삭제됩니다.)


가정이 데이터에 적용되는지 여부를 판단할 수 있도록 작동 방식은 다음과 같습니다.
첫째, "드롭아웃"으로 인해 발생하는 0의 보간입니다. 선형 보간이 선택되었습니다. splines와 quadratics를 고려했지만 결과는 내 눈에 열등했습니다.
아래 행 4-6의 "보간된 전력" 열을 통해 "Cum Zeros Behind"를 확인하십시오.
"Cum Zeros Behind"는 0에 대한 포괄적인 룩백입니다.
"Cum Zeros Ahead"는 0에 대한 포괄적인 예측입니다.
"0 블록"은 블록에서 연속된 0의 수입니다.
"0에 대한 그룹"은 1에서 시작하여 새로운 0 그룹이 발생할 때마다 증가합니다.
보간은 행 1에서 시작하지 않고 짧은(7개 미만) 0 블록이 있을 때 발생합니다.
****참고: 샘플 데이터에서 가장 긴 보간 사례는 4개의 0에 걸쳐 있는 반면 간격 사이의 가장 짧은 "참" 중단은 7개의 0이었습니다. 이는 오류에 대한 아주 적은 마진이며 이 접근 방식의 중요한 단점일 수 있습니다. 가장 짧은 "실제" 브레이크가 가장 긴 "드롭아웃"보다 길다는 것이 중요합니다.
이전에 언급한 바와 같이 이러한 열은 대부분 필요하지 않지만 보간 공식이 열 없이는 훨씬 보기 흉해지고 문제 해결이 (훨씬) 어려워집니다.

보간 후에는 최소 7개의 연속된 0이 있는 블록만 데이터에 남습니다(제외된 처음 몇 행에서 발생할 수 있는 0).
"간격" 열은 데이터를 그룹화합니다. 1부터 시작하여 다음과 같이 증가할 때마다 증가합니다.
-타임스탬프가 100 이상 변경되거나
-보간된 거듭제곱은 0에서 0이 아닌 값으로 이동합니다.
"Post-spike" 열은 전력이 스파이크에서 안정(ish) 상태로 감소하는 동안 설정되는 플래그입니다.
0으로 (재)설정됩니다.
- 행 1
- 간격 열이 변경될 때마다
- 새로운 0 블록이 발생할 때마다
보간된 전력이 90보다 큰 값에서 90 이하의 전력으로 이동할 때마다 1로 설정됩니다. 샘플의 데이터를 기반으로 이것은 합리적으로 보였습니다.

이제 무시할 데이터("무시" 열의 목적)를 결정할 수 있습니다. 다음 중 하나에 해당하는 경우 데이터를 무시합니다.
- 간격에 대한 최대값은 < 400입니다. (이것은 "배경 소음"입니다). 다시 말하지만, 제공된 데이터를 기반으로 합니다.
- 보간된 파워는 스파이크 이후 100 이상으로 이동합니다. (우리가 0으로 내려가는 대신 "배경 잡음"으로 이동했음을 나타냄)
- 보간 전력은 0입니다.
"Final Power"는 "Interpolated Power"와 동일하지만 "Ignore" == 1인 경우 누락으로 설정됩니다.
"간격 시간"은 간격에 상대적인 시간을 계산합니다(즉, 0에서 시작하여 거기에서 증분). "Final Power"와 마찬가지로 "Ignore" == 1일 때마다 누락으로 설정됩니다.
나는 수식 평가를 비활성화하지 않고 무시되지 않은 데이터를 부분 집합화하지 않았지만 이것이 다음 단계일 가능성이 높습니다.
Dan이 다음에 이것을 어떻게 깨뜨리는 지 보는 것은 흥미로울 것입니다 
건배,
브래디
Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별지금까지의 모든 솔루션은 다음과 같습니다. JMP 공개:
Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별이것은 정말 좋은 해결책입니다. 에 출력을 게시했습니다. JMP 공개 로컬 데이터 필터를 사용하여 새 데이터 세트, 세 가지 교육 실행 및 이진 정상 상태의 기능 열을 확인합니다.
Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별@Daniel_Valente ,
여기 도전에 대한 나의 시도가 있습니다.
내 접근 방식은 모티프의 시작과 끝에서 기능을 식별하고 전체 실행 영역(시작과 끝 사이)을 식별한 다음 각각에 주제 ID를 할당하는 것입니다.
다음은 내가 사용한 열 수식에 대한 코드입니다.
names default to here(1);
dt = current data table();
// date from time stamp
dt << New Column( "Date[timestamp]",
Numeric,
Nominal,
Format( "yyyy-mm-dd", 19 ),
Input Format( "yyyy-mm-dd" ),
Formula( :timestamp - Time Of Day( :timestamp ) )
);
// rate of change
dt << New Column( "rate of change",
Numeric,
Continuous,
Formula(
Col Moving Average(
Dif(
Col Moving Average(
:power / Col Maximum( :power, :Name( "Date[timestamp]" ) ),
0.6,
5,
5,
Empty(),
:Name( "Date[timestamp]" )
)
)
,
0.95,
5,
5,
Empty(),
:Name( "Date[timestamp]" )
)
)
);
// Start point
dt << New Column( "Start Point",
Numeric,
Continuous,
Formula(
If( Row() == 1,
0,
checkZero = 1 * (:power[Row()] > 0 & :power[Row() - 1] == 0);
foundPeak = 0;
For( k = Row() + 1, k <= N Rows(), k++,
If( :power[k] > Col Quantile( :power, 0.93, :Name( "Date[timestamp]" ) ),
foundPeak = 1;
Break();
);
If( :power[k] == 0, Break() );
);
If( checkZero == 1 & foundPeak == 1,
1,
0
);
)
)
);
// steady state
dt << New Column( "Steady State",
Numeric,
Continuous,
Formula(
ans = 1;
For( k = 0, k <= 10, k++,
ans = Minimum(
ans,
1 * (:rate of change[Row() - k] < 0.003 &
:rate of change[Row() - k] > -0.003)
)
);
ans;
)
);
// Run Region
dt << New Column( "Run Region",
Numeric,
Continuous,
Format( "Best", 12 ),
Formula(
ans = 0;
For( k = Row(), k >= 1, k--,
If( :Start Point[k] == 1,
ans = 1;
Break();
);
If( :Steady State[k] == 0 & :Steady State[k - 1] == 1,
ans = 0;
Break();
);
);
ans;
)
);
// motif ID
dt << New Column( "Motif ID",
Numeric,
Nominal,
Formula(
If(
:Run Region == 1,
Col Cumulative Sum( :Start Point )
)
)
);
// rank timestamp, Motif ID - helps plot each motif
dt << New Column( "Rank[timestamp]",
Numeric,
Continuous,
Formula( Col Rank( :timestamp, :Motif ID ) )
);Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별좋아, Byron -- 이거 꽤 좋아 보인다. 두 노이즈 곡선을 선택합니다. 주말 동안 추가 데이터를 수집하고 공정한지 확인하겠습니다.

Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별멋진! 그것도 좋은 해결책처럼 들립니다. 파헤칠 수 있는 경우 JSL을 게시하면 시도하겠습니다.
Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별흠. 좋은 질문입니다. 데이터 문제에 대해 생각할 때 항상 가정을 탐색하는 것이 좋습니다. 또한 데이터를 생성하는 시스템을 소유한 사람들에게 물어보십시오!
1) 세션당 단 한 번의 쿨다운 워밍업. 워밍업은 그렇게 많이 다르지 않습니다. 커피 몇 잔을 마시지 않는 한 평균은 ~250 +-30와트입니다...

2) 보시다시피 저는 최고 속도를 6-10초 동안만 유지할 수 있고 그 다음에는 힘이 떨어지기 시작합니다. 아마도 미래에는 더 길고/더 넓어질 것입니다. 우리는 그것을 탐구해야 할 것입니다.
3) 보행 기간 이후의 0은 포함되지 않아야 합니다. 재설정 기간입니다. 처음부터 거의 0 와트 준비입니다. 일정 시간 동안 스프린트. 정지할 때까지 속도를 줄이십시오. 뒤로 걸어가십시오. 다음 간격 세트를 위해 0으로 돌아갑니다.
4) 모티프 중 0은 잘못된 데이터이므로 보간해야 합니다. 나는 멈추지 않았다. 센서가 떨어졌을 뿐입니다. 수정하거나 누락된 것으로 표시하거나 보간해야 합니다. 그렇지 않으면 후속 분석에서 몇 가지 문제가 발생하는 것을 볼 수 있습니다.
Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별AI 모델을 포함하도록 간단한 열 수식 접근 방식을 변경했습니다. 이제 테이블에는 몇 가지 더 간단한 수식과 함께 환상적으로 복잡한 수식이 하나 있습니다.
첨부된 스크립트는 열과 그래프를 추가합니다. 모델은 곡선 세그먼트를 신호 또는 노이즈로 채점합니다.
고유한 데이터 세트에 점수를 매기는 방법에 관심이 있습니다.

Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별나는 열 충격 오븐의 온도 주기를 세는 직장에서 약간 비슷한 일을 했습니다. 이 경우 몇 가지 다른 수식 열을 사용하여 수행했다고 생각합니다. 작업 중인 코드를 살펴보고 이 경우에 대해 수정할 수 있는지 확인해야 합니다.
내가 올바르게 기억한다면 내 아이디어는 사이클의 "시작점"(이 경우 0 전력 및 마지막 값 가져 오기)을 감지 한 다음 일부 임계 값을 초과하는 충분한 값이 있는지 확인하십시오 (여기서는 5 값 이상일 수 있음) 350) 그런 다음 사이클이 끝나는 곳을 확인합니다(80-100 사이의 ~20 값이 있는 평평한 부분). 그런 다음 필요에 따라 늘리고 재설정할 몇 가지 실행 변수(motid_id, cycle_ongoing, ...)가 있습니다.
Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별가정이 중요합니다. 데이터에 대해 무엇을 가정하시겠습니까? 당신의 문제가 있을 곳에 있습니다.
1) 얼마나 많은 쿨다운/워밍업이 가능합니까? 이들의 평균 전력을 알고 있습니까? 다양합니까?
2) 모티프의 길이는 다양할 수 있습니다... 그러나 항상 비슷한 길이를 가집니까? 지금까지의 샘플 데이터에서는 이랬습니다. 앞으로도 그럴까요?
3) 0은 어떻습니까? 그것들을 모티프의 앞부분으로 포함해야 할까요, 말아야 할까요? 그들 모두, 그들 중 특정 숫자, 그들 중 아무도 없습니까?
4) 모티프 중간에 발생하는 0은 어떻습니까? 합법적입니까? 모티프 중간에 0이 아닌 점은 어떻습니까? 이것이 합법적인지 어떻게 알 수 있습니까? 노력해야 할까요?
등등등
건배,
브래디
Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별다음은 다음과 연결된 세 번째 파일입니다. @Byron_JMP 의 스크립트입니다. 같은 현상이 발생하는 것 같습니다. 제외할 부분의 일부를 모티브로 태깅하고 있습니다. 좋은 점은 동일한 지점에서 또는 동일한 실패 모드를 사용하여 실패하는 것 같습니다. 사이클 그룹 9 및 18과 샘플/파워 플롯에서도 이를 볼 수 있습니다.


Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별우! 멋진 @Byron_JMP . 수식 열 솔루션이 마음에 듭니다. 방금 크기를 조정하려고했습니다. 그것은 다른 방식으로 실패합니다 @brady_brady 의 솔루션입니다.
Motif 9은 약간 수상해 보입니다...

Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별어 오! 이것을 확장하려고 할 때 문제가 발생합니다. 이제 이틀간의 데이터가 있습니다. Brady의 스크립트를 실행하여 희망적으로 16개의 모티프를 식별했습니다.
지금 들어오는 새 데이터가 있고 스크립트를 실행했습니다. @brady_brady 썼다. 16개의 모티프를 올바르게 식별했습니다. 그런데 지금 8화에 이상한 점이 있습니다. 알고리즘이 새로운 데이터로 인해 혼란스러워하는 것 같습니다. 타임스탬프가 있습니다. 이 스케일을 만드는 데 도움이 될 수 있을까요?


시도해 보기 @Byron_JMP 의 솔루션입니다.
Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별@brady_brady 그것은 문제를 해결하는 꽤 매끄러운 방법입니다.
세 가지 간단한 열 수식으로 했습니다.

new column("time point", formula(If( Row() == 1,
1,
If( :power == 0 & Lag( :time point, 1 ) <= 50,
Lag( :time point, 1 ) + 1,
If( :power == 0,
1,
Lag( :time point, 1 ) + 1
)
)
)));
new column("segments", formula(
If(
Row() == 1, 0,
:time point == 1, Lag( :segments, 1 ) + 1,
Lag( :segments, 1 )
)));
new column("cycle", formula(
If( :time point > 70 | :segments == 0,
.,
:segments
)));Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별멋지다, 브래디! 훌륭한 일. 일부 데이터 품질 문제가 있다는 것도 흥미롭습니다. 피크 모델을 적용하여 이를 부드럽게 할 수 있습니다. 실제로 0이 아니거나 보간되지 않았기 때문에 누락된 것으로 표시될 수 있습니까?Re: JMP 워크플로 챌린지 1: 연속 전력 데이터에서 모티프 추출 및 식별단일 수식 열로 얼마나 많은 결과를 얻을 수 있는지는 놀랍습니다.
dt << new column("Motif ID", nominal, formula(Col Cumulative Sum(
Row() > 6 & Summation( i = 1, 6, Abs( Lag( :power, i ) ) ) == 0 & :power != 0
)));
그러나 아직 정리해야 할 부분이 있습니다. 이 접근 방식은 선행 데이터인 "0" 그룹 ID를 생성하고 원하는 마지막 모티프를 잘라내지 않습니다. 합계에서 "6"은 전원 변경 전에 최소 6개의 연속된 0이 발생하면 새 그룹을 지정하기 때문입니다.
물론 백그라운드 플로어와의 비교, 공격/붕괴 등을 포함하는 더 정교한 다른 많은 방법이 있지만 이와 같은 간단한 접근 방식이 작동한다면 훌륭합니다.
아래 스크립트는 이 아이디어를 통합하지만 데이터 세트도 정리합니다. 이상적으로는 마지막 몇 줄의 값이 매개변수화됩니다.
names default to here(1);
dt = current data table();
dtSub = dt << subset(selected rows(0), selected columns(0));
//create ID column
dtSub << new column("Motif ID", nominal, formula(Col Cumulative Sum(
Row() > 6 & Summation( i = 1, 6, Abs( Lag( :power, i ) ) ) == 0 & :power != 0
)));
dtSub:MotifID << delete formula;
//the next 2 loops truncate the dataset, assuming it ends like the sample dataset ended.
for(i = nrow(dtSub), abs(dtSub:power[i] - dtSub:power[i-1]) < 20, i--,
dtSub << Delete Rows(i)
);
for(i = nrow(dtSub), abs(dtSub:power[i] - dtSub:power[i-1]) > 5, i--,
dtSub << Delete Rows(i)
);
//delete ID 0 group
dtSub << select where(:Motif ID == 0) << delete rows;
//delete 0 power rows, but not when they lie within a group
i = nrow(dtSub)-1;
while (i > 1,
if(dtSub:Motif ID[i] < dtSub:MotifID[i+1] & dtSub:power[i] == 0,
while( dtSub:power[i] == 0,
dtSub << delete rows(i--);
)
);
i--
);

JMP 워크플로 과제 1: 연속 전력 데이터에서 모티프 추출 및 식별
JMP 워크플로 및 JSL 마법사 호출. 여기 당신을 위한 목요일 챌린지가 있습니다. 첨부된 데이터 세트는 내 러닝 파워 미터의 전원 데이터 세트입니다. 우리가 원하는 것은 이 게시물에 첨부된 이 ~1000 포인트 신호 데이터 세트 중에 발생하는 8개의 모티프를 식별하고 올바르게 태그하고 기능 ID로 새 열을 만들고 태그 지정을 자동화하는 데 사용할 수 있는 방식으로 작성하는 것입니다. 이 동일한 엔벨로프를 따르는 미래 데이터.
이 데이터 세트와 미래에 대한 데이터 수집 가정은 다음과 같습니다.
- 모티프가 시작되기 전에는 거듭제곱이 0입니다.
- 0이 아닌 모티프(워밍업 및 워밍다운) 전후 기간이 있습니다. 이것은 테스트 중인 시스템의 일부가 아니므로 태그를 지정하면 안 됩니다.
- 각 모티프에는 어택, 서스테인, 디케이 및 릴리스가 있습니다. 기능의 모양은 모티프마다 동일합니다. 샘플 기간 동안 0에서 최고점까지 이동한 다음 기준선 노이즈 플로어(워킹 파워)까지 감소합니다. 전원이 다시 0이 되면 주제 ID가 종료됩니다.
- 앞으로 식별해야 할 기능의 수는 알려지지 않을 것입니다. 데이터 세트에는 8개가 있습니다. 솔루션은 이에 대해 불변해야 합니다.
- 기능의 전체 길이와 피크는 다를 수 있습니다.
우리는 왼쪽 가장자리에서 작업하고 있습니다. 분석 워크플로우 오늘(아래 녹색으로 표시됨). 데이터는 파일(.csv)에서 가져오며 결국 이 워크플로우를 자동화했을 때 N .csv 파일. 데이터 액세스가 사용되고 있으며 현재 작업은 이 예제 파일에서 데이터 혼합 및 정리 작업을 수행하여 향후 다른 분석 기능으로 워크플로를 확장할 수 있도록 데이터를 준비하는 것입니다.

의견에 솔루션을 남겨주세요.
데이터 혼합 및 정리