从文件和其他源加载数据

了解如何使用 API 将数据加载到 ML.NET 中进行处理和训练。 最初存储在文件或其他数据源(例如数据库、JSON、XML 或内存中集合)中的数据。

如果使用模型生成器,请参阅将训练数据加载到模型生成器

创建数据模型

ML.NET 允许通过类定义数据模型。 例如,给定以下输入数据:

Size (Sq. ft.), HistoricalPrice1 ($), HistoricalPrice2 ($), HistoricalPrice3 ($), Current Price ($)
700, 100000, 3000000, 250000, 500000
1000, 600000, 400000, 650000, 700000

创建一个表示以下代码片段的数据模型:

public class HousingData
{
    [LoadColumn(0)]
    public float Size { get; set; }

    [LoadColumn(1, 3)]
    [VectorType(3)]
    public float[] HistoricalPrices { get; set; }

    [LoadColumn(4)]
    [ColumnName("Label")]
    public float CurrentPrice { get; set; }
}

使用列属性批注数据模型

特性为 ML.NET 提供有关数据模型和数据源的详细信息。

LoadColumn 特性指定属性的列索引。

重要

只有从文件加载数据时才需要 LoadColumn

将列加载为:

  • 各个列,例如 HousingData 类中的 SizeCurrentPrices
  • 以向量的形式一次加载多个列,例如 HousingData 类中的 HistoricalPrices

如果有一个向量属性,请在数据模型中向该属性应用 VectorType 特性。 向量中的所有元素都必须是同一类型。 保持列与列之间的分隔状态可以提高特征工程的易用性和灵活性,但是对于大量的列,在单个列上操作会对训练速度产生影响。

ML.NET 通过列名称进行操作。 如果要将某个列的名称更改为该属性名称以外的其他名称,请使用 ColumnName 特性。 创建内存中对象时,仍然使用该属性名称创建对象。 但是,对于数据处理和生成机器学习模型,ML.NET 使用 ColumnName 特性中提供的值覆盖并引用该属性。

从单个文件加载数据

若要从文件加载数据,请使用 LoadFromTextFile 方法以及要加载的数据的数据模型。 由于 separatorChar 参数默认为制表符分隔,因此请根据需要为数据文件更改该参数。 如果文件有标头,请将 hasHeader 参数设置为 true,以忽略文件中的第一行并开始从第二行加载数据。

//Create MLContext
MLContext mlContext = new MLContext();

//Load Data
IDataView data = mlContext.Data.LoadFromTextFile<HousingData>("my-data-file.csv", separatorChar: ',', hasHeader: true);

从多个文件加载数据

如果数据存储在多个文件中,只要数据架构相同,ML.NET 就允许从同一目录或多个目录中的多个文件加载数据。

从单个目录中的文件加载

当所有数据文件位于同一目录中时,请在 LoadFromTextFile 方法中使用通配符。

//Create MLContext
MLContext mlContext = new MLContext();

//Load Data File
IDataView data = mlContext.Data.LoadFromTextFile<HousingData>("Data/*", separatorChar: ',', hasHeader: true);

从多个目录中的文件加载

若要从多个目录加载数据,请使用 CreateTextLoader 方法创建 TextLoader。 然后,使用 TextLoader.Load 方法并指定单个文件路径(不能使用通配符)。

//Create MLContext
MLContext mlContext = new MLContext();

// Create TextLoader
TextLoader textLoader = mlContext.Data.CreateTextLoader<HousingData>(separatorChar: ',', hasHeader: true);

// Load Data
IDataView data = textLoader.Load("DataFolder/SubFolder1/1.txt", "DataFolder/SubFolder2/1.txt");

从关系数据库加载数据

ML.NET 支持从各种关系数据库中加载数据(包括 SQL Server、Azure SQL 数据库、Oracle、SQLite、PostgreSQL、Progress、IBM DB2 等),这些关系数据库由 System.Data 提供支持。

注意

若要使用 DatabaseLoader,请参考 System.Data.SqlClient NuGet 包。

指定具有名为 House 的表和以下架构的数据库:

CREATE TABLE [House] (
    [HouseId] INT NOT NULL IDENTITY,
    [Size] INT NOT NULL,
    [NumBed] INT NOT NULL,
    [Price] REAL NOT NULL
    CONSTRAINT [PK_House] PRIMARY KEY ([HouseId])
);

数据可以通过 HouseData 等类进行建模:

public class HouseData
{
    public float Size { get; set; }
    public float NumBed { get; set; }
    public float Price { get; set; }
}

然后,在应用程序中创建 DatabaseLoader

MLContext mlContext = new MLContext();

DatabaseLoader loader = mlContext.Data.CreateDatabaseLoader<HouseData>();

定义连接字符串以及要在数据库上执行的 SQL 命令,并创建 DatabaseSource 实例。 此示例使用具有文件路径的 LocalDB SQL Server 数据库。 但是,DatabaseLoader 支持本地和云中数据库的任何其他有效连接字符串。

重要

Microsoft 建议使用最安全的可用身份验证流。 如果要连接到 Azure SQL,建议使用 Azure 资源的托管标识这种身份验证方法。

string connectionString = @"Data Source=(LocalDB)\MSSQLLocalDB;AttachDbFilename=<YOUR-DB-FILEPATH>;Database=<YOUR-DB-NAME>;Integrated Security=True;Connect Timeout=30";

string sqlCommand = "SELECT CAST(Size as REAL) as Size, CAST(NumBed as REAL) as NumBed, Price FROM House";

DatabaseSource dbSource = new DatabaseSource(SqlClientFactory.Instance, connectionString, sqlCommand);

类型不是 Real 的数值数据必须转换为 RealReal 类型表示为单精度浮动点值或 Single,这是 ML.NET 算法应采用的输入类型。 在此示例中,SizeNumBed 列是数据库中的整数。 使用 CAST 内置函数,将其转换为 Real。 由于 Price 属性的类型已经是 Real,所以它按原样加载。

使用 Load 方法将数据加载到 IDataView

IDataView data = loader.Load(dbSource);

加载图像

若要从目录中加载图像数据,请先创建一个包含图像路径和标签的模型。 ImagePath 是图像在数据源目录中的绝对路径。 Label 是实际图像文件的类或类别。

public class ImageData
{
    [LoadColumn(0)]
    public string ImagePath;

    [LoadColumn(1)]
    public string Label;
}

public static IEnumerable<ImageData> LoadImagesFromDirectory(string folder,
            bool useFolderNameAsLabel = true)
{
    string[] files = Directory.GetFiles(folder, "*", searchOption: SearchOption.AllDirectories);

    foreach (string file in files)
    {
        if (Path.GetExtension(file) != ".jpg")
            continue;

        string label = Path.GetFileName(file);

        if (useFolderNameAsLabel)
            label = Directory.GetParent(file).Name;
        else
        {
            for (int index = 0; index < label.Length; index++)
            {
                if (!char.IsLetter(label[index]))
                {
                    label = label.Substring(0, index);
                    break;
                }
            }
        }

        yield return new ImageData()
        {
            ImagePath = file,
            Label = label
        };
    }
}

然后加载图像:

IEnumerable<ImageData> images = LoadImagesFromDirectory(
                folder: "your-image-directory-path",
                useFolderNameAsLabel: true
                );

若要从目录中加载内存中原始图像,请创建一个模型来保存原始图像字节数组和标签:

public class InMemoryImageData
{
    [LoadColumn(0)]
    public byte[] Image;

    [LoadColumn(1)]
    public string Label;
}

static IEnumerable<InMemoryImageData> LoadInMemoryImagesFromDirectory(
    string folder,
    bool useFolderNameAsLabel = true
    )
{
    string[] files = Directory.GetFiles(folder, "*",
        searchOption: SearchOption.AllDirectories);
    foreach (string file in files)
    {
        if (Path.GetExtension(file) != ".jpg")
            continue;

        string label = Path.GetFileName(file);
        if (useFolderNameAsLabel)
            label = Directory.GetParent(file).Name;
        else
        {
            for (int index = 0; index < label.Length; index++)
            {
                if (!char.IsLetter(label[index]))
                {
                    label = label.Substring(0, index);
                    break;
                }
            }
        }

        yield return new InMemoryImageData()
        {
            Image = File.ReadAllBytes(file),
            Label = label
        };

    }
}

从其他源加载数据

除了加载存储在文件中的数据外,ML.NET 还支持从各种源加载数据,这些源包括:

  • 内存中集合
  • JSON/XML

在使用流式处理源时,ML.NET 预计输入采用内存中集合的形式。 因此,在使用 JSON/XML 等源时,请确保将数据格式化为内存中集合。

给定以下内存中集合:

HousingData[] inMemoryCollection = new HousingData[]
{
    new HousingData
    {
        Size =700f,
        HistoricalPrices = new float[]
        {
            100000f, 3000000f, 250000f
        },
        CurrentPrice = 500000f
    },
    new HousingData
    {
        Size =1000f,
        HistoricalPrices = new float[]
        {
            600000f, 400000f, 650000f
        },
        CurrentPrice=700000f
    }
};

使用 LoadFromEnumerable 方法将内存中集合加载到 IDataView 中:

重要

LoadFromEnumerable 假定其所加载的 IEnumerable 是线程安全的。

// Create MLContext
MLContext mlContext = new MLContext();

//Load Data
IDataView data = mlContext.Data.LoadFromEnumerable<HousingData>(inMemoryCollection);

后续步骤