У меня есть большая матрица (30000 x 500), столбец представляет почасовые данные в течение следующих 3 лет, каждый столбец - это другой сценарий, то есть у меня есть 500 сценариев цены, где каждая ячейка в строке имеет одну и ту же метку времени.Самый эффективный способ агрегации матриц в C# и ILNumerics vs Matlab
Мне нужно агрегировать это по оси времени, поэтому, если ежедневно мне нужно сделать матрицу (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? Моя последняя строка выше не работает.
UPDATE:
Я добавил более настоятельную версию без 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.
Update 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, но я сомневаюсь, что она будет быстрее.
Что было плохо, как вы пробовали? – Reniuz
Я добавил свою попытку, но она не делает трюк еще – nik
для простого среднего по столбцам, который можно использовать: ['ILMath.mean'] (http://ilnumerics.net/apidoc/?topic=html/M_ILNumerics_ILMath_mean_3. htm) или ['ILMath.sum'] (http://ilnumerics.net/apidoc/?topic=html/M_ILNumerics_ILMath_sum_3.htm) –