在 Engee 中使用工作空间数组
WorkspaceArray "是*Engee*建模环境中的一种特殊数据类型,用于存储和处理时间序列。它基于Julia 语言的 AbstractArray
接口,但与标准数组不同的是,它实现了数据的 "懒加载"(Lazy Loading),这使它成为一个懒数组。
懒数组(或懒加载数组)是一种不将数据完全存储在 RAM 中,而是在需要时加载数据的结构:例如,在迭代、按索引访问或转换为表时。这样就能有效地处理内存中无法容纳或来自外部(如数据库或文件)的超大数据集。
在 Engee 中的 WorkspaceArray
可用于以下情况:
-
作为模拟结果,存储记录的信号。例如,在
simout
变量中(详见软件处理 Engee 中的模拟结果 ); -
通过块To Workspace 和From Workspace 在模型之间传输数据;
-
从 CSV 文件或表格(
DataFrame
)中导入自定义时间序列,然后将其用于 Engee 模型。
因此,"WorkspaceArray "为整个模拟过程(从输入数据准备到结果分析)中访问时间序列数据提供了一个单一而方便的接口。
创建工作区数组
通常,"WorkspaceArray "是在仿真过程中自动生成的,例如,通过 To Workspace 块写入信号或将结果保存到simout 变量时。
但也可以手动创建,例如加载外部数据或使用预先准备好的输入测试模型。在这种情况下,"WorkspaceArray" 可以通过以下方式之一创建:
-
*从 CSV 文件。要从 CSV 文件加载数据,只需指定文件路径即可:
wa = WorkspaceArray("my_wa", "/user/path_to_csv.csv")
"my_wa "是数组保存在可变窗口
Engee 中的名称。它用于在模型、脚本和其他应用程序中进一步引用数组。
CSV 文件必须包含两列:一列*必须*命名为 "时间",另一列必须包含信号值。CSV 文件结构示例:
time value 0.1 1 0.2 2 0.3 3
-
*从 "DataFrame "表中创建。如果你已经在 Julia 中处理表格数据,你可以直接从一个
DataFrame
对象创建一个WorkspaceArray
。这在数据分析或转换过程中以编程方式生成输入时尤其有用。DataFrame
是DataFrames.jl
包中的一种表格结构,类似于 Excel 中的表格或 Python (pandas) 中的 DataFrames。每一列都有名称和类型,数据按行存储。创建示例using DataFrames df = DataFrame(time = [0.1, 0.2, 0.3], value = [1, 2, 3]) wa = WorkspaceArray("my_wa", df)
表格必须包含两列:时间"(类型为 "Float64")和 "值"(可以是标量、向量或数字数组)。
使用工作区数组
工作区数组 "实现了 "抽象数组 "接口,因此可以像 Julia 中的普通数组一样处理它—索引、迭代、切分等。不过,除了基本的数组行为外,WorkspaceArray
还包含一个内部结构和额外的字段,这些字段提供了与数据源的连接,支持懒加载并允许方便地处理时间序列。
每个 WorkspaceArray
都不仅仅是一组数字,而是一个具有 "元数据 "的对象:它知道自己的数据在哪里、与时间的关系如何、从哪里加载以及如何获得。只需通过点引用对象的字段,就可以直接查询这些附加属性:
wa = WorkspaceArray("my_wa")
wa.time # доступ к временны́м меткам
wa.value # доступ к значениям
wa.type # узнаем, какой тип у массива — :pair, :time или :value
可使用以下字段:
-
time
- 仅包含时间戳的子WorkspaceArray
。它具有:time
类型; -
value
- 包含信号值的子`工作区数组`。其类型为:value
; -
type
- 当前数组的类型::time
、:value
或:pair
(时间戳 + 值); -
parent
- 如果当前数组是切分的结果,则引用父数组WorkspaceArray
; -
range
- 创建切片所依据的索引范围。它用于懒切分; -
dimension
-value
字段中数据的维度(例如,标量、向量、矩阵); -
signal_id
- 数据源在 Engee 中的唯一标识符。
在使用 WorkspaceArray 时,通常会直接使用 time 和 value 字段,尤其是需要单独获取数据或将其转换为表格时。
|
重复使用
包含 WorkspaceArray
的变量(例如名为 wa
)一旦创建,就会自动链接到 Engee 中的 signal_id
(唯一标识符)。这样,它就可以通过名称被引用,并在项目的其他部分重复使用—例如,在基于 Genie 框架的网络应用程序中(见在 Engee 中使用 Genie ),在其他模型中,或在嵌套块中,如Subsystem :
wa = WorkspaceArray("my_wa")
这样的条目会创建一个新的 WorkspaceArray
以 `"my_wa"`为名引用已注册的数据。
与模型一起使用
To Workspace 和 From Workspace 块旨在与模型中的 WorkspaceArray
进行交互:
To Workspace 程序块将模型中的数据写入 Engee 工作区中的一个类型为 WorkspaceArray
的变量。变量名由 Variable name 参数指定。只支持数值数据(标量和数组)。
From Workspace 程序块从工作区读取数据并将其输入模型输入端。只使用 WorkspaceArray
类型的变量。
到工作区 "和 "从工作区 "程序块只能*使用 "工作区数组 "类型。 |
使用示例从/到工作区演示。
卸载数据
完全卸载到 DataFrame
要将数据从 WorkspaceArray
完全卸载到 DataFrame,请使用 collect
:
df = collect(wa) # получаем DataFrame с колонками time и value
您还可以从 WorkspaceArray
中获取单列数据:
collect(wa.time) # только время
collect(wa.value) # только значения
不建议对非常大的数据使用 collect ,因为可能会出现内存超载。
|
懒切片
WorkspaceArray` 的主要优点之一是支持*懒切片*(Lazy Slices)。
与普通的 Julia 数组不同,WorkspaceArray`的切片(`wa[1:10]
)是用数据副本创建一个新数组。切片创建的视图只存储索引范围(range
)和对原始对象(parent
)的引用,而不会将数值实际加载到内存中。只有在明确查询(如通过 collect
、迭代或索引访问)时,才会从内存中加载数据。
这对以下情况特别有用
-
节省内存—切片不会复制数据,只会指向所需的项目;
-
性能快 - 只需使用必要的数据分片即可;
-
灵活性—懒切片可用作模型输入、可视化或导出。
示例
wa_slice = wa[1:2:end] # ленивое представление: каждый второй элемент
collect(wa_slice) # загружаем данные в память (в виде DataFrame)
结果:
Row │ time value
│ Float64 Int64
────┼───────────────
1 │ 0.1 1
2 │ 0.3 3
3 │ 0.5 5
除切片外,您还可以通过索引访问单个元素:
wa[1] # доступ к первой записи, будет получено (0.1, 1)
按 "时间 "和 "值 "字段切片
在 WorkspaceArray
中有单独的 .time
和 .value
字段,您也可以对它们应用懒切分:
wa_values = wa.value[2:end] # срез только по значениям
wa_times = wa.time[2:end] # срез только по временной шкале
wa[1:2:end]`片段会返回一个类型为`WorkspaceArray`的对象,其`signal_id`相同,但有一个新的`range`字段指向该片段。这让你知道你面对的是一个*lazy view*,而不是数据的副本。 如有必要,可将数据加载到内存中:
|
工作区数组方法和接口
WorkspaceArray "实现了标准的 Julia 接口,并用自己的方法对其进行了扩充。下面简要介绍了在处理时间序列时最有用的函数:
-
wa[i]
- 通过索引访问元素,返回元组(时间, 值)
:wa[1] # будет получено (0.1, 42.0)
-
wa[start:stop]
- 按范围切分,返回懒视图。数据不会被复制,而是根据需要加载:wa_slice = wa[1:10] collect(wa_slice) # загружает только выбранный диапазон
-
wa[1:2:end]
- 以增量为单位的懒切片。 -
wa.time
,wa.value
- 访问分别包含时间和数值的子WorkspaceArray
。切片也可应用于它们:wa_times = wa.time[5:end] wa_values = wa.value[5:end]
-
collect(wa)` - 将
WorkspaceArray
转换为DataFrame
。这是显式获取数据的主要方法:df = collect(wa)
-
copy(wa)
/similar(wa)
- 创建对象的表面副本。在当前的实现中,它们的工作方式相同。 -
wa1 == wa2
- 通过signal_id
和范围 (range
)对两个WorkspaceArray
进行比较。
如果您在*Engee*中处理时间序列,那么`collect`、slices (wa[1:10] )和`iterrows`可能就足以胜任日常工作。其余的方法将有助于优化和微调行为。
|
使用示例
让我们来看一个使用 WorkspaceArray
的基本示例—从创建到获取切片和卸载数据。该示例涵盖了 WorkspaceArray
最典型的使用场景。
-
首先,创建一个包含两列的表(
DataFrame
):时间 "和 "值"。这是导入数据到WorkspaceArray
的必备格式:using DataFrames df = DataFrame(time = [0.1, 0.2, 0.3, 0.4, 0.5], value = [1, 2, 3, 4, 5])
-
time
- 时间点(以秒为单位); -
value
- 此时的信号值。
-
-
将表格转换为`WorkspaceArray`,指定数组在 Engee 中的名称:
wa = WorkspaceArray("myarr", df)
这里,
"myarr"
是在模型和脚本中使用的变量名。 -
工作区数组支持按索引访问。例如,获取第一条记录:
println(wa[1])
结果:
(0.1, 1)
这是一个元组:第一个元素是时间,第二个元素是信号值。
数据只有在被访问时才会被加载。也就是说,即使使用 wa[1]
也只加载一个元素。 -
对数组进行切片,获取每一个其他元素
(1,3,5)
。这将创建一个*简单的表示法*,而不是拷贝:wa_slice = wa[1:2:end]
要以表格形式获取数据,请使用
collect
:println(collect(wa_slice))
结果:
3×2 DataFrame Row │ time value │ Float64 Int64 ─────┼──────────────── 1 │ 0.1 1 2 │ 0.3 3 3 │ 0.5 5
wa[1:2:end]
切分本身不会加载数据。只有在调用 `collect
、迭代或索引时,才会从存储空间实际加载数据。