time_series_search: 조건이 유지되는 구간 찾기
foundryts.functions.time_series_search(
predicate, labels=None, start=None, end=None, interval_values=None,
before='nearest', internal='default', after='nearest',
min_duration=None, max_duration=None
)
시계열 하나 이상에서 predicate가 참인 구간을 찾고 각 구간의 통계를 반환하는 함수를 만듭니다. 이 구간은 Quiver의 이벤트에 대응합니다. 관측값을 직접 검색하는 기능이며, 객체 속성으로 시계열 참조를 찾는 Search와 구분합니다.
검색과 통계 인수
| 인수 | 형식 | 기본값과 의미 |
|---|---|---|
| predicate | str | 구간을 찾는 DSL 조건식 |
| labels | str 또는 List[str] | 입력 시계열의 별칭. 기본은 a, b부터 aa, ab 등으로 이어짐 |
| start | int, datetime 또는 str | None. 검색 시작 시각 포함. 기본 하한은 pandas.Timestamp.min |
| end | int, datetime 또는 str | None. 검색 종료 시각 제외. 기본 상한은 pandas.Timestamp.max |
| interval_values | str | 구간 통계를 계산할 값의 DSL 식. 기본은 첫 입력 시계열 |
| min_duration | int, str 또는 datetime.timedelta | None. 구간으로 인정할 최소 지속 시간 |
| max_duration | int, str 또는 datetime.timedelta | None. 구간으로 인정할 최대 지속 시간 |
start 또는 end와 겹치는 구간은 전체 구간을 반환합니다. 검색 경계에 맞춰 구간을 잘라 반환하는 방식이 아니므로, 반환 구간의 시작이나 끝이 검색 범위를 벗어날 수 있습니다.
통계는 숫자형 값을 필요로 합니다. 범주형 시계열을 입력으로 사용하면 interval_values에 숫자형 결과를 만드는 식을 지정해야 합니다. 여러 입력 중 숫자형 시계열을 통계 대상으로 선택할 수도 있습니다.
보간 인수
| 인수 | 형식 | 기본 동작 |
|---|---|---|
| before | str 또는 List[str] | NEAREST. 첫 관측 이전 |
| internal | str 또는 List[str] | default. 숫자형 LINEAR, 범주형 PREVIOUS |
| after | str 또는 List[str] | NEAREST. 마지막 관측 이후 |
목록으로 지정하면 입력 순서대로 전략을 적용합니다. 허용 전략은 interpolate, 조건 및 값 식은 dsl을 사용합니다.
반환 결과
반환한 요약 질의를 DataFrame으로 평가하면 구간마다 통계 한 행을 얻습니다. 다음은 가상 결과에서 사용하는 필드입니다. 다른 계산에 경계를 연결할 때는 평가한 DataFrame의 columns에서 실제 경계 열 이름을 확인하여 명시적으로 선택합니다.
| 열 | 형식 | 의미 |
|---|---|---|
| start_time | datetime | 구간 시작, 포함 |
| end_time | datetime | 구간 끝, 제외 |
| count | int | 구간의 관측 수 |
| earliest_point.timestamp | datetime | 첫 관측 시각 |
| earliest_point.value | float | 첫 관측값 |
| latest_point.timestamp | datetime | 마지막 관측 시각 |
| latest_point.value | float | 마지막 관측값 |
| smallest_point.timestamp | datetime | 최솟값 관측 시각 |
| smallest_point.value | float | 최솟값 |
| largest_point.timestamp | datetime | 최댓값 관측 시각 |
| largest_point.value | float | 최댓값 |
| mean | float | 관측값 평균 |
| standard_deviation | float | 관측값 표준편차 |
| duration.seconds | int | 지속 시간의 초 부분 |
| duration.subsecond_nanos | int | 지속 시간의 초 미만 나노초 부분 |
구간 경계로 Interval을 만들고 NodeCollection.map_intervals에 전달하면 각 구간을 별도 시계열로 나누어 계산할 수 있습니다.
가상 숫자형 입력
import foundryts.functions as F
discrete_series = F.points(
(0, 1.0),
(1, 2.0),
(2, 2.0),
(3, 3.0),
(4, 5.0),
(5, 6.0),
(6, 4.0),
(7, 2.0),
(8, 6.0),
(9, 7.0),
(10, 8.0),
(11, 10.0),
(12, 11.0),
name="discrete",
)
이후 표의 시각은 모두 Unix epoch 이후 나노초이며 각 구간의 duration.seconds는 0입니다. 괄호로 표시한 관측은 (시각 ns, 값)입니다.
짝수 값의 구간
even_search = F.time_series_search(
predicate="discrete % 2 == 0",
interval_values="discrete",
labels="discrete",
)(discrete_series)
interval_df = even_search.to_pandas()
result_columns = list(interval_df.columns)
짝수 관측이 이어지는 구간은 세 개입니다.
| start_time(ns) | end_time(ns) | 포함 관측 | count | duration.subsecond_nanos | mean | standard_deviation |
|---|---|---|---|---|---|---|
| 1 | 3 | (1, 2), (2, 2) | 2 | 2 | 2.0 | 0.0 |
| 5 | 9 | (5, 6), (6, 4), (7, 2), (8, 6) | 4 | 4 | 4.5 | 1.658312 |
| 10 | 12 | (10, 8), (11, 10) | 2 | 2 | 9.0 | 1.0 |
각 행의 끝점과 극값 정보는 다음과 같습니다.
| 구간 시작(ns) | earliest_point | latest_point | smallest_point | largest_point |
|---|---|---|---|---|
| 1 | (1, 2.0) | (2, 2.0) | (2, 2.0) | (2, 2.0) |
| 5 | (5, 6.0) | (8, 6.0) | (7, 2.0) | (8, 6.0) |
| 10 | (10, 8.0) | (11, 10.0) | (10, 8.0) | (11, 10.0) |
구간은 그대로 두고 통계 값을 변환
doubled_values = F.time_series_search(
predicate="discrete % 2 == 0",
interval_values="discrete * 2",
labels="discrete",
)(discrete_series)
doubled_df = doubled_values.to_pandas()
predicate는 그대로이므로 경계, 관측 수와 지속 시간은 같은 세 구간입니다. interval_values가 각 값을 두 배로 만든 뒤 통계를 계산합니다.
| 구간 시작(ns) | mean | standard_deviation | earliest_point | latest_point | smallest_point | largest_point |
|---|---|---|---|---|---|---|
| 1 | 4.0 | 0.0 | (1, 4.0) | (2, 4.0) | (2, 4.0) | (2, 4.0) |
| 5 | 9.0 | 3.316625 | (5, 12.0) | (8, 12.0) | (7, 4.0) | (8, 12.0) |
| 10 | 18.0 | 2.0 | (10, 16.0) | (11, 20.0) | (10, 16.0) | (11, 20.0) |
지속 시간 조건
최소 3나노초를 요구하면 길이가 2인 첫 구간과 마지막 구간을 제외합니다.
minimum_duration = F.time_series_search(
predicate="discrete % 2 == 0",
interval_values="discrete",
labels="discrete",
min_duration="3ns",
)(discrete_series)
minimum_df = minimum_duration.to_pandas()
결과는 [5, 9) 한 구간이며 count=4, mean=4.5, standard_deviation=1.658312입니다. 끝점과 극값은 기본 검색의 해당 행과 같습니다.
최대 3나노초를 지정하면 길이가 4인 가운데 구간을 제외합니다.
maximum_duration = F.time_series_search(
predicate="discrete % 2 == 0",
interval_values="discrete",
labels="discrete",
max_duration="3ns",
)(discrete_series)
maximum_df = maximum_duration.to_pandas()
결과는 [1, 3)과 [10, 12)이며 각 행의 통계는 기본 검색과 같습니다.
범주형 조건으로 다른 시계열 분석
상태를 나타내는 가상 toggle 시계열을 추가합니다.
toggle_series = F.points(
(0, "OFF"),
(1, "ON"),
(2, "OFF"),
(3, "OFF"),
(4, "ON"),
(5, "ON"),
(6, "ON"),
(7, "OFF"),
(8, "ON"),
(9, "ON"),
(10, "OFF"),
(11, "OFF"),
(12, "ON"),
name="toggle",
)
cross_series = F.time_series_search(
predicate='toggle == "ON"',
interval_values="discrete",
labels=["toggle", "discrete"],
)([toggle_series, discrete_series])
cross_series_df = cross_series.to_pandas()
첫 입력의 상태가 ON인 구간을 찾고 두 번째 숫자형 입력의 값으로 통계를 계산합니다. 가상 결과는 다음 네 구간입니다.
| start_time(ns) | end_time(ns) | 포함된 discrete 관측 | count | duration.subsecond_nanos | mean | standard_deviation |
|---|---|---|---|---|---|---|
| 1 | 2 | (1, 2) | 1 | 1 | 2.0 | 0.0 |
| 4 | 7 | (4, 5), (5, 6), (6, 4) | 3 | 3 | 5.0 | 0.816497 |
| 8 | 10 | (8, 6), (9, 7) | 2 | 2 | 6.5 | 0.5 |
| 12 | 13 | (12, 11) | 1 | 1 | 11.0 | 0.0 |
| 구간 시작(ns) | earliest_point | latest_point | smallest_point | largest_point |
|---|---|---|---|---|
| 1 | (1, 2.0) | (1, 2.0) | (1, 2.0) | (1, 2.0) |
| 4 | (4, 5.0) | (6, 4.0) | (6, 4.0) | (5, 6.0) |
| 8 | (8, 6.0) | (9, 7.0) | (8, 6.0) | (9, 7.0) |
| 12 | (12, 11.0) | (12, 11.0) | (12, 11.0) | (12, 11.0) |