Engee 文档

在 Engee 中使用工作空间数组

WorkspaceArray "是*Engee*建模环境中的一种特殊数据类型,用于存储和处理时间序列。它基于Julia 语言的 AbstractArray 接口,但与标准数组不同的是,它实现了数据的 "懒加载"(Lazy Loading),这使它成为一个懒数组。

懒数组(或懒加载数组)是一种不将数据完全存储在 RAM 中,而是在需要时加载数据的结构:例如,在迭代、按索引访问或转换为表时。这样就能有效地处理内存中无法容纳或来自外部(如数据库或文件)的超大数据集。

Engee 中的 WorkspaceArray 可用于以下情况:

因此,"WorkspaceArray "为整个模拟过程(从输入数据准备到结果分析)中访问时间序列数据提供了一个单一而方便的接口。

创建工作区数组

通常,"WorkspaceArray "是在仿真过程中自动生成的,例如,通过 至工作区 块写入信号或将结果保存到simout 变量时。

但也可以手动创建,例如加载外部数据或使用预先准备好的输入测试模型。在这种情况下,"WorkspaceArray" 可以通过以下方式之一创建:

  • *从 CSV 文件。要从 CSV 文件加载数据,只需指定文件路径即可:

    wa = WorkspaceArray("my_wa", "/user/path_to_csv.csv")

    "my_wa "是数组保存在可变窗口 variables article 2 1 Engee 中的名称。它用于在模型、脚本和其他应用程序中进一步引用数组。

    CSV 文件必须包含两列:一列*必须*命名为 "时间",另一列必须包含信号值。CSV 文件结构示例:

    time    value
    0.1     1
    0.2     2
    0.3     3
  • *从 "DataFrame "表中创建。如果你已经在 Julia 中处理表格数据,你可以直接从一个 DataFrame 对象创建一个 WorkspaceArray 。这在数据分析或转换过程中以编程方式生成输入时尤其有用。

    DataFrameDataFrames.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 时,通常会直接使用 timevalue 字段,尤其是需要单独获取数据或将其转换为表格时。

重复使用

包含 WorkspaceArray 的变量(例如名为 wa)一旦创建,就会自动链接到 Engee 中的 signal_id(唯一标识符)。这样,它就可以通过名称被引用,并在项目的其他部分重复使用—​例如,在基于 Genie 框架的网络应用程序中(见在 Engee 中使用 Genie ),在其他模型中,或在嵌套块中,如子系统

wa = WorkspaceArray("my_wa")

这样的条目会创建一个新的 WorkspaceArray 以 `"my_wa"`为名引用已注册的数据。

与模型一起使用

至工作区来自工作区 块旨在与模型中的 WorkspaceArray 进行交互:

至工作区 程序块将模型中的数据写入 Engee 工作区中的一个类型为 WorkspaceArray 的变量。变量名由 Variable name 参数指定。只支持数值数据(标量和数组)。

来自工作区 程序块从工作区读取数据并将其输入模型输入端。只使用 WorkspaceArray 类型的变量。

到工作区 "和 "从工作区 "程序块只能*使用 "工作区数组 "类型。

使用示例从/到工作区演示

使用 CSV

将工作区数组导出为 CSV

要将 WorkspaceArray 导出为 CSV,请使用 CSV.write,并强制使用参数 delim="\t"

using CSV
CSV.write("/user/workspacearray_csv.csv", delim="\t", data_frame)
如果没有 delim="\t" 参数,在导入时将导致 BoundsError 并创建一个空文件。

从 CSV 导入工作区数组

wa = WorkspaceArray("my_wa", "/user/my_data.csv")

文件必须包含两列:

  • time - 必填列名;

  • value - 值。

卸载数据

完全卸载到 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*,而不是数据的副本。

如有必要,可将数据加载到内存中:

wa = WorkspaceArray("my_wa")

wa_slice = wa[1:2:end]     # создаем ленивый срез
df = collect(wa_slice)     # загрузка данных
println(df)                # получаем таблицу со срезанными значениями

工作区数组方法和接口

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 最典型的使用场景。

  1. 首先,创建一个包含两列的表(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 - 此时的信号值。

  2. 将表格转换为`WorkspaceArray`,指定数组在 Engee 中的名称:

    wa = WorkspaceArray("myarr", df)

    这里,"myarr" 是在模型和脚本中使用的变量名。

  3. 工作区数组支持按索引访问。例如,获取第一条记录:

    println(wa[1])

    结果:

    (0.1, 1)

    这是一个元组:第一个元素是时间,第二个元素是信号值。

    数据只有在被访问时才会被加载。也就是说,即使使用 wa[1] 也只加载一个元素。
  4. 对数组进行切片,获取每一个其他元素 (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、迭代或索引时,才会从存储空间实际加载数据。