1

私も構築している別の.NETアプリケーションによって維持されるデータを分析するために使用されるMatlabコンポーネントのインターフェイスレイヤーを構築しています。.NET データテーブルを数値配列としてシリアル化し、MATLAB コンポーネントに (より一般化されたシリアル化ルーチンの一部として) 渡そうとしています。

これまでのところ、数値データのテーブルを渡すことにはかなり成功していますが、 datatype の列を追加しようとすると問題が発生しましたDateTime。これまで私が行ってきたことは、値をDataTabledouble 配列に詰め込むことでした。これは、MATLAB が実際に double のみを気にするためです。次に、MWNumericArray本質的に行列である a に直接キャストします。

これが現在のコードです。

else if (sourceType == typeof(DataTable))
{
    DataTable dtSource = source as DataTable;
    var rowIdentifiers = new string[dtSource.Rows.Count];               
    // I know this looks silly but we need the index of each item
    // in the string array as the actual value in the array as well
    for (int i = 0; i < dtSource.Rows.Count; i++)
    {
        rowIdentifiers[i] = i.ToString();
    }
    // convenience vars
    int rowCount = dtSource.Rows.Count;
    int colCount = dtSource.Columns.Count;
    double[,] values = new double[rowCount, colCount];

    // For each row 
    for (int rownum = 0; rownum < rowCount; rownum++)
    {
        // for each column
        for (int colnum = 0; colnum < colCount; colnum++)
        {
            // ASSUMPTION. value is a double
            values[rownum, colnum] = Conversion.ConvertToDouble(dtSource.Rows[rownum][colnum]);
        }
    }
    return (MWNumericArray)values;
}

Conversion.ConvertToDoubleこれも、Matlab がすべての NULLS を NaN として扱うため、NULL、DBNull に対応し、double.NaN を返す私自身のルーチンです。

これが問題です。複数のデータ型を持つ連続した配列を渡すことができる MATLAB データ型を知っている人はいますか? 私が考えることができる唯一の回避策は、 of を使用することMWStructArrayですMWStructArraysが、それはハッキーに思えますし、MATLAB コードでうまく機能するかどうかもわかりません。そのため、できればより洗練された解決策を見つけたいと思います。の使用を検討しましたが、MWCellArrayインスタンス化しようとするとコンパイル エラーが発生します。

次のようなことができるようになりたいです。

object[,] values = new object[rowCount, colCount];
// fill loosely-typed object array
return (MWCellArray)values;

しかし、私が言ったように、オブジェクト配列をコンストラクターに渡すことでもコンパイルエラーが発生します。

ばかげたことを見逃した場合はお詫び申し上げます。私はいくつかのグーグルを実行しましたが、Matlab から .NET インターフェイスへの情報は少し軽いように思われるため、ここに投稿しました。

前もって感謝します。

[編集]

提案してくれたみんなに感謝します。

私たちの特定の実装のための最も迅速で最も効率的な方法は、SQL コードで Datetime を int に変換することでした。

ただし、他のアプローチのうち、MWCharArray アプローチを使用することをお勧めします。それは大騒ぎを最小限に抑え、私が間違ったことをしただけであることが判明しました.MWNumericsまたはあなたが行くようにあなたの空想を取るものは何でも。注意すべきことの 1 つは、MWArray が 0 ベースではなく 1 ベースであることです。それは私を捕まえ続けます。

時間があれば、今日の後半でより詳細な議論に入る予定ですが、今はしていません。ご協力いただきありがとうございます。

4

4 に答える 4

6

@Mattがコメントで示唆したように、異なるデータ型 (数値、文字列、構造体など) を格納する場合は、このマネージ API によって公開されるセル配列に相当するもの、つまりMWCellArrayクラスを使用する必要があります。

説明のために、単純な .NET アセンブリを実装しました。セル配列 (データベース テーブルからのレコード) を受け取る MATLAB 関数を公開し、単純に出力します。この関数は、 sample を生成する C# アプリケーションから呼び出され、それを(セルごとにテーブル エントリを埋める)DataTableに変換します。MWCellArray

秘訣は、 に含まれるオブジェクトを、派生クラスDataTableによってサポートされる型にマップすることです。MWArray私が使用したものは次のとおりです(完全なリストについては、ドキュメントを確認してください)。

.NET native type          MWArray classes
------------------------------------------
double,float,int,..       MWNumericArray
string                    MWCharArray
DateTime                  MWNumericArray       (using Ticks property)

日付/時刻データに関する注意: .NET では、System.DateTimeは日付と時刻を次のように表します。

0001 年 1 月 1 日 00:00:00.000 から経過した 100 ナノ秒間隔の数

MATLAB では、これがDATENUM関数の意味です。

シリアル日付数値は、特定の日時からの整数および小数の日数を表します。ここで、datenum('Jan-1-0000 00:00:00') は数値 1 を返します。

このため、DateTimeシリアル日付番号の MATLAB 定義と一致するように「ティック」を変換するために、C# アプリケーションに 2 つのヘルパー関数を記述しました。


まず、この単純な MATLAB 関数について考えてみましょう。テーブル データを含む numRos 行 numCols 列の cellarray を受け取ることを想定しています。私の例では、列は次のとおりです。名前 (string)、価格 (double)、日付 (DateTime)

function [] = my_cell_function(C)
    names = C(:,1);
    price = cell2mat(C(:,2));
    dt = datevec( cell2mat(C(:,3)) );

    disp(names)
    disp(price)
    disp(dt)
end

MATLAB Builder NE のdeploytoolを使用して、上記を .NET アセンブリとしてビルドします。次に、C# コンソール アプリケーションを作成MWArray.dllし、上記で生成されたものに加えて、アセンブリへの参照を追加します。これは私が使用しているプログラムです:

using System;
using System.Data;
using MathWorks.MATLAB.NET.Utility;  // MWArray.dll
using MathWorks.MATLAB.NET.Arrays;   // MWArray.dll
using CellExample;                   // CellExample.dll assembly created

namespace CellExampleTest
{
    class Program
    {
        static void Main(string[] args)
        {
            // get data table
            DataTable table = getData();

            // create the MWCellArray
            int numRows = table.Rows.Count;
            int numCols = table.Columns.Count;
            MWCellArray cell = new MWCellArray(numRows, numCols);   // one-based indices

            // fill it cell-by-cell
            for (int r = 0; r < numRows; r++)
            {
                for (int c = 0; c < numCols; c++)
                {
                    // fill based on type
                    Type t = table.Columns[c].DataType;
                    if (t == typeof(DateTime))
                    {
                        //cell[r+1,c+1] = new MWNumericArray( convertToMATLABDateNum((DateTime)table.Rows[r][c]) );
                        cell[r + 1, c + 1] = convertToMATLABDateNum((DateTime)table.Rows[r][c]);
                    }
                    else if (t == typeof(string))
                    {
                        //cell[r+1,c+1] = new MWCharArray( (string)table.Rows[r][c] );
                        cell[r + 1, c + 1] = (string)table.Rows[r][c];
                    }
                    else
                    {
                        //cell[r+1,c+1] = new MWNumericArray( (double)table.Rows[r][c] );
                        cell[r + 1, c + 1] = (double)table.Rows[r][c];
                    }
                }
            }

            // call MATLAB function
            CellClass obj = new CellClass();
            obj.my_cell_function(cell);

            // Wait for user to exit application
            Console.ReadKey();
        }

        // DateTime <-> datenum helper functions
        static double convertToMATLABDateNum(DateTime dt)
        {
            return (double)dt.AddYears(1).AddDays(1).Ticks / (10000000L * 3600L * 24L);
        }
        static DateTime convertFromMATLABDateNum(double datenum)
        {
            DateTime dt = new DateTime((long)(datenum * (10000000L * 3600L * 24L)));
            return dt.AddYears(-1).AddDays(-1);
        }

        // return DataTable data
        static DataTable getData()
        {
            DataTable table = new DataTable();
            table.Columns.Add("Name", typeof(string));
            table.Columns.Add("Price", typeof(double));
            table.Columns.Add("Date", typeof(DateTime));

            table.Rows.Add("Amro", 25, DateTime.Now);
            table.Rows.Add("Bob", 10, DateTime.Now.AddDays(1));
            table.Rows.Add("Alice", 50, DateTime.Now.AddDays(2));

            return table;
        }
    }
}

コンパイルされた MATLAB 関数によって返されるこの C# プログラムの出力:

'Amro'
'Bob'
'Alice'

25
10
50

     2011            9           26           20           13       8.3906
     2011            9           27           20           13       8.3906
     2011            9           28           20           13       8.3906
于 2011-09-26T17:25:50.870 に答える
2

1 つのオプションは、matlab から直接 .NET コードを開き、説明したこのシリアル化プロセスを実行する代わりに、.net インターフェイスを使用して matlab にデータベースを直接クエリさせることです。私はこれを私たちの環境で繰り返し行い、大きな成功を収めました。そのような努力 Net.addAssemblyでは、あなたの最大の友人です。

詳細はこちら。 http://www.mathworks.com/help/matlab/ref/net.addassembly.html

2 番目のオプションは、Matlab セル配列を使用することです。列が異なるデータ型になり、各列がセルを形成するように設定できます。これは、matlab 自体が textscan 関数で使用するトリックです。ここでその関数のドキュメントを読むことをお勧めします: http://www.mathworks.com/help/techdoc/ref/textscan.html

3 番目のオプションは、textscan を完全に使用することです。.net コードからテキスト ファイルを書き出し、textscan にその解析を処理させます。Textscan は、この種のデータを matlab に取り込むための非常に強力なメカニズムです。textscan をファイルまたは一連の文字列に向けることができます。

于 2011-09-23T16:11:21.860 に答える
0

@Amro によって作成された関数を試しましたが、特定の日付の結果が正しくありません。

私が試したのは:

  1. C# で日付を作成する
  2. 関数を使用して、@Amro が提供する Matlab 日付 num に変換します
  3. その番号を Matlab で使用して、その正確性を確認します

2014年、2015年など、いくつかの年の1 Jan 00:00:00の日付に問題があるようです。たとえば、

DateTime dt = new DateTime(2014, 1, 1, 0, 0, 0);
double dtmat = convertToMATLABDateNum(dt);

これから dtmat = 735599.0 を得ました。次のようにMatlabで使用しました:

datestr(datenum(735599.0))

お返しにこれをもらいました:

ans = 31-Dec-2013

2012 年 1 月 1 日に試したときは問題ありませんでした。任意の提案またはなぜこれが起こるのですか?

于 2015-08-05T12:12:14.837 に答える