[英]Most efficient way of matrix aggregation in c# and ILNumerics vs Matlab
我有一個大矩陣(30000 x 500),一列表示未來3年的每小時數據,每列是不同的情況,即我有500個價格情況,其中行中的每個單元格都具有相同的時間戳。
我需要在時間軸上進行匯總,因此如果每天我都需要制作一個(30000 / nrdays x 500),每月(30000 / nrmonths x 500)矩陣,並且顯然還要保留正確的日期。
在matlab中,我創建了一個每天或每個月都有唯一編號的索引,然后使用以下方法遍歷各列:
accumarray(idx,price(:,i),[numel(unique(idx)) 1], @mean)
如果我想在C#中執行此操作,最好的方法是什么?
以下是我到目前為止的內容:
public class matrixwihtdates
{
public DateTime dats;
public ILArray<double> nums;
}
public class endres
{
public string year;
public string month;
public string day;
public ILArray<double> nums;
}
public static List<endres> aggrmatrix(ILArray<double> origmatrix, DateTime std, DateTime edd)
{
var aggrmatr = new List<matrixwihtdates>();
for (int i = 0; i < origmatrix.Length; i++)
{
aggrmatr.Add(new matrixwihtdates
{
dats = std.AddHours(i),
nums = origmatrix[i, "full"],
});
}
return aggrmatr.GroupBy(a => new { yr = a.dats.Year, mt = a.dats.Month })
.Select(g => new endres {
year = g.Key.yr.ToString(),
month = g.Key.mt.ToString(),
nums = ILMath.mean(g.Select(a => a.nums).ToArray(),1) }).ToList();
}
關鍵問題是,我不知道如何對LINQ語法中的每一列求平均值,以便返回向量(1x500)。 還是不應該使用LINQ? 我上面的最后一行不起作用。
更新:
我添加了一個不帶LINQ的命令式版本,這似乎可行,但仍然有些笨拙。
public static List<ILArray<double>> aggrmatrixImp(ILArray<double> origmatrix, DateTime std)
{
List<ILArray<double>> aggrmatr = new List<ILArray<double>>();
ILArray<double> tempmatrix;
int startindicator = 0;
int endindicator = 0;
int month = std.Month;
for (int i = 0; i < origmatrix.Length; i++)
{
if (std.AddHours(i).Month != month)
{
endindicator = i - 1;
tempmatrix = origmatrix[ILMath.r(startindicator, endindicator), ILMath.r(0, ILMath.end)];
aggrmatr.Add(ILMath.mean(tempmatrix, 1));
startindicator = i;
month = std.AddHours(i).Month;
}
}
return aggrmatr;
}
我仍然想使LINQ版本正常工作。
更新2
我考慮了Haymo的建議,這是另一個快兩倍的版本。
public static ILArray<double> aggrmatrixImp2(ILArray<double> origmatrix, DateTime firstdateinfile, DateTime std, DateTime edd)
{
int nrmonths = ((edd.Year - std.Year) * 12) + edd.Month - std.Month;
ILArray<double> aggrmatr = ILMath.zeros(nrmonths,500);
int startindicator = std.Date.Subtract(firstdateinfile.Date).Duration().Days*24;
int endindicator = 0;
DateTime tempdate = std.AddMonths(1);
tempdate = new DateTime(tempdate.Year, tempdate.Month, 1);
for (int i = 0; i < nrmonths; i++)
{
endindicator = tempdate.Date.Subtract(std.Date).Duration().Days * 24-1;
aggrmatr[i, ILMath.full] = ILMath.mean(origmatrix[ILMath.r(startindicator, endindicator), ILMath.full], 1);
tempdate = tempdate.AddMonths(1);
startindicator = endindicator+1;
}
return aggrmatr;
}
我沒有可用的LINQ版本,但我懷疑它會更快。
您的更新版本更適合ILNumerics中處理數組的方式。
對LINQ和ILNumerics.ILArray<T>
所述IEnumerable<T>
其被用於枚舉的ILArray<T>
過在列主順序的所有元素進行迭代。 參見此處: http : //ilnumerics.net/blog/ilnumerics-and-linq/
ILNumerics已針對您在問題更新中使用的命令式,面向數組的版本進行了優化。 如果您仍然決定使用Linq,建議您手動在Linq語句中進行匯總,而不要依賴ILMath.mean
。
您可以嘗試按如下所示(隨機順序)從更新中優化第二個示例:
1)將結果保存在矩陣( ILArray<double> aggrmatr
)中,而不是List<ILArray<double>>
。 如果還要存儲日期,也可以使用ILCell
。 但是您的示例僅存儲匯總的數字。 因此, ILArray<double>
就足夠了。
2)預分配結果ILArray<double>
並遍歷其行(而不是遍歷origmatrix
的行)-恰好一次 。 結果行數應該事先知道,對吧? 至少如果日期行表示日期/時間,則可以根據tempmatrix中的當前行計算開始和結束指示符,並像以前一樣使用它們。
3)使用ILMath.full
或":"
表示子ILMath.full
表達式中的完整尺寸。
4)使用ILNumerics函數規則 ! 您的矩陣足夠大,因此由於內存池和更有效的並行化,很有可能會加快速度。
5)將函數表示在從ILMath派生的類中,可以通過省略ILMath來帶來更好的語法ILMath.
所有表達式(如ILMath.r(...
, ILMath.mean
。
另外,將ILArray用作類屬性時要記住的一些規則(如您的第一個示例)請參見: http : //ilnumerics.net/ClassRules.html
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.