Skip to content

Commit 89a0de1

Browse files
committed
time series blocks
1 parent b60afa8 commit 89a0de1

File tree

9 files changed

+415
-32
lines changed

9 files changed

+415
-32
lines changed

src/FastAI.jl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,9 @@ include("Tabular/Tabular.jl")
115115
include("Textual/Textual.jl")
116116
@reexport using .Textual
117117

118+
include("TimeSeries/TimeSeries.jl")
119+
@reexport using .TimeSeries
120+
118121
include("deprecations.jl")
119122
export
120123
methodmodel,
@@ -178,6 +181,7 @@ export
178181
Continuous,
179182
Image,
180183
Paragraph,
184+
TimeSeriesRow,
181185

182186
# encodings
183187
encode,

src/TimeSeries/TimeSeries.jl

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
module TimeSeries
2+
3+
4+
using ..FastAI
5+
using ..FastAI:
6+
# blocks
7+
Block, WrapperBlock, AbstractBlock, OneHotTensor, OneHotTensorMulti, Label,
8+
LabelMulti, wrapped, Continuous, getencodings, getblocks, encodetarget, encodeinput,
9+
# encodings
10+
Encoding, StatefulEncoding, OneHot,
11+
# visualization
12+
ShowText,
13+
# other
14+
Context, Training, Validation
15+
16+
# for tests
17+
using ..FastAI: testencoding
18+
19+
# extending
20+
import ..FastAI:
21+
blockmodel, blockbackbone, blocklossfn, encode, decode, checkblock,
22+
encodedblock, decodedblock, showblock!, mockblock, setup
23+
24+
import Requires: @require
25+
26+
using FilePathsBase
27+
using InlineTest
28+
29+
# Blocks
30+
include("blocks/timeseriesrow.jl")
31+
32+
include("recipes.jl")
33+
34+
function __init__()
35+
_registerrecipes()
36+
end
37+
38+
export TimeSeriesRow
39+
40+
end
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
"""
2+
TimeSeriesRow{M,N}() <: Block
3+
4+
[`Block`](#) for a M variate time series with N number of time steps. `obs` is valid for `TimeSeriesRow{M,N}()`
5+
if it is an (M,N) dimensional Matrix with number element type.
6+
7+
## Examples
8+
9+
Creating a block:
10+
11+
```julia
12+
TimeSeriesRow{1,51}() # Univariate time series with length 51.
13+
TimeSeriesRow{2,51}() # Multivariate time series with 2 variables and length 51.
14+
```
15+
16+
You can create a random observation using [`mockblock`](#):
17+
18+
{cell=main}
19+
```julia
20+
using FastAI
21+
FastAI.mockblock(TimeSeriesRow{1,10}())
22+
```
23+
24+
"""
25+
26+
struct TimeSeriesRow{M,N} <: Block end
27+
28+
function checkblock(::TimeSeriesRow{M,N}, obs::AbstractArray{T,2}) where {M,N,T<:Number}
29+
size(obs) == (M,N)
30+
end
31+
32+
mockblock(::TimeSeriesRow{M,N}) where {M,N} = rand(Float64, (M,N))
33+
34+
function setup(::Type{TimeSeriesRow}, data)
35+
N, M = size(getobs(data, 1))
36+
return TimeSeriesRow{N,M}()
37+
end

src/TimeSeries/makie.jl

Whitespace-only changes.

src/TimeSeries/recipes.jl

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
"""
2+
TimeSeriesDatasetRecipe(file; loadfn = loadfile)
3+
4+
Recipe for loading a time series dataset stored in a .ts file
5+
6+
"""
7+
Base.@kwdef struct TimeSeriesDatasetRecipe <: Datasets.DatasetRecipe
8+
train_file
9+
test_file = nothing
10+
loadfn = loadfile
11+
end
12+
13+
Datasets.recipeblocks(::Type{TimeSeriesDatasetRecipe}) = Tuple{TimeSeriesRow, Label}
14+
15+
#TODO: Add Check if test_file is nothing.
16+
function Datasets.loadrecipe(recipe::TimeSeriesDatasetRecipe, path)
17+
path = convert(String, path)
18+
datasetpath_train = joinpath(path, recipe.train_file)
19+
rows_train, labels_train = recipe.loadfn(datasetpath_train)
20+
datasetpath_test = joinpath(path, recipe.test_file)
21+
rows_test, labels_test = recipe.loadfn(datasetpath_test)
22+
rows = [rows_train; rows_test]
23+
labels = [labels_train; labels_test]
24+
rows = TimeSeriesDataset(rows)
25+
data = rows, labels
26+
blocks = (
27+
setup(TimeSeriesRow,rows),
28+
Label(unique(eachobs(labels))),
29+
)
30+
return data, blocks
31+
end
32+
33+
# Registering recipes
34+
35+
const RECIPES = Dict{String,Vector{Datasets.DatasetRecipe}}(
36+
"ecg5000" => [
37+
TimeSeriesDatasetRecipe(train_file="ECG5000_TRAIN.ts", test_file="ECG5000_TEST.ts")
38+
],
39+
)
40+
41+
function _registerrecipes()
42+
for (name, recipes) in RECIPES, recipe in recipes
43+
if !haskey(datarecipes(), name)
44+
push!(datarecipes(), (
45+
id = name,
46+
datasetid = name,
47+
blocks = Datasets.recipeblocks(recipe),
48+
package = @__MODULE__,
49+
recipe = recipe,
50+
))
51+
end
52+
end
53+
end
54+
55+
# ## Tests
56+
57+
@testset "TimeSeriesDataset [recipe]" begin
58+
path = datasetpath("ecg5000")
59+
recipe = TimeSeriesDatasetRecipe(train_file="ECG5000_TRAIN.ts", test_file="ECG5000_TEST.ts")
60+
data, block = loadrecipe(recipe, path)
61+
sample = getobs(data, 1)
62+
@test checkblock(block, sample)
63+
end

src/datasets/Datasets.jl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,12 @@ export
6565
# primitive containers
6666
FileDataset,
6767
TableDataset,
68+
TimeSeriesDataset,
6869

6970
# utilities
7071
isimagefile,
7172
istextfile,
73+
istimeseriesfile,
7274
matches,
7375
loadfile,
7476
loadmask,

0 commit comments

Comments
 (0)