Самый эффективный способ агрегации матриц в c # и ILNumerics против Matlab

1

У меня есть большая матрица (30000 x 500), столбец представляет почасовые данные в течение следующих 3 лет, каждый столбец - это другой сценарий, т.е. У меня 500 сценариев цен, где каждая ячейка в строке имеет одну и ту же метку времени.

Мне нужно агрегировать это по оси времени, поэтому, если ежедневно мне нужно создать матрицу (30000/nrdays x 500), если ежемесячно (30000/nrmonths x 500) и, очевидно, также сохранить правильные даты.

В Matlab я создал индекс с уникальным номером для каждого дня или каждого месяца, а затем зациклился на столбцах, используя это:

accumarray(idx,price(:,i),[numel(unique(idx)) 1], @mean)

Если я хочу сделать это в С#, что лучший способ?

ниже - то, что у меня есть до сих пор:

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, но я сомневаюсь, что она будет быстрее.

  • 0
    Какой плохой способ ты пробовал?
  • 0
    Я добавил свою попытку, но она еще не успокоилась
Показать ещё 3 комментария
Теги:
linq
ilnumerics

1 ответ

2
Лучший ответ

Ваша версия обновления соответствует тому, как массивы должны обрабатываться в 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> полученный ILArray<double> и ILArray<double> его строки (а не через строки origmatrix) - ровно один раз. Количество результирующих строк должно быть известно заранее, правильно? По крайней мере, если строки дат представляют даты/время, вы можете вычислить начало и конец указателя в соответствии с текущей строкой в tempmatrix и использовать это, как и вы.

3) Используйте ILMath.full или ":" чтобы указать полное измерение в выражении подмассива.

4) Используйте правила функции ILNumerics ! Ваши матрицы достаточно велики, так что это, скорее всего, даст некоторое ускорение из-за пула памяти и более эффективного распараллеливания.

5) Формулирование вашей функции в классе, полученном из ILMath, приводит к значительно более сильному синтаксису, позволяя вам опустить ILMath. идентификатор для всех выражений, таких как ILMath.r(..., ILMath.mean.

Кроме того, некоторые правила, которые следует учитывать при использовании ILArray в качестве атрибутов класса (как в первом примере), см. По адресу: http://ilnumerics.net/ClassRules.html

Ещё вопросы

Сообщество Overcoder
Наверх
Меню