C # LINQ для ранжирования значений временных рядов на ежедневной основе => деление по дате, затем ранжирование по значению (от наибольшего к наименьшему) - PullRequest
2 голосов
/ 08 марта 2011

У меня есть набор из около 2000 отдельных временных рядов в виде SortedList<DateTime,double>. Каждая серия соответствует ежедневной ликвидности для данной ценной бумаги. Я хотел бы создать ежедневный рейтинг этих значений. Если бы я делал это для циклов for, я бы сделал следующее:

  1. Создайте новый пустой временной ряд [date, (int) rank] для каждой ценной бумаги, чтобы удерживать ее рейтинг в данный день. Это может быть в форме SortedList<DateTime,double>.
  2. Создан список всех уникальных дат (не каждый временной ряд ценных бумаг имеет значение для каждой даты.)
  3. Для каждой уникальной даты проведите цикл по каждому временному ряду ежедневной ликвидности ценных бумаг, чтобы определить, имеет ли оно значение на эту дату.
  4. Если это так, добавьте имя и значение ценной бумаги в массив ежедневного рейтинга [SecName, значение ликвидности].
  5. Сортировка массива от наибольшего к наименьшему (ранг 1 = наибольшее значение).
  6. Для каждой ценной бумаги (secName) в массиве добавьте дату и рейтинг ценных бумаг к его временному ряду (созданному на шаге 1).

Проще говоря, это ежедневный рейтинг ликвидности от самой большой до самой маленькой. Я могу заставить linq извлекать данные из объектов и групп по дате, но остальное выходит за рамки моих навыков в linq.

Любые мастера linq хотят дать этому шанс?

Упрощенная версия структуры объекта изложена ниже.

Примечание. Я специально создал одну дату (2011,01,18), в которой значения (30) совпадают. В этом случае субрейнинг по имени символа является приемлемым. Таким образом, они будут ранжированы ... 1-й 6753 JT, 2-й 6754 JT. 6752 JT не имеет значения на эту дату, поэтому оно не будет включено.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Ranking_Query
{
    class Program
    {
        static void Main(string[] args)
        {
            // created an instance of the datasource and add 3 securities to it
            Datasource ds = new Datasource() { Name = "test" };

            ds.securities.Add("6752 JT", new Security() { 
                timeSeries = new Dictionary<string, SortedList<DateTime, double>>() {
                    { "liquidity", new SortedList<DateTime, double>() { 
                        {new DateTime(2011,01,15),30},
                        {new DateTime(2011,01,16),20},
                        {new DateTime(2011,01,17),10} } } }
            });

            ds.securities.Add("6753 JT", new Security()
            {
                timeSeries = new Dictionary<string, SortedList<DateTime, double>>() {
                    { "liquidity", new SortedList<DateTime, double>() { 
                        {new DateTime(2011,01,15),20},
                        {new DateTime(2011,01,16),30},
                        {new DateTime(2011,01,17),20},
                        {new DateTime(2011,01,18),30} } } }
            });

            ds.securities.Add("6754 JT", new Security()
            {
                timeSeries = new Dictionary<string, SortedList<DateTime, double>>() {
                    { "liquidity", new SortedList<DateTime, double>() { 
                        {new DateTime(2011,01,16),10},
                        {new DateTime(2011,01,17),30},
                        {new DateTime(2011,01,18),30} } } }
            });


        }

        class Datasource
        {
            public string Name { get; set; }
            public Dictionary<string, Security> securities = new Dictionary<string, Security>();
        }

        class Security
        {
            public string symbol { get; set; }
            public Dictionary<string, SortedList<DateTime, double>> timeSeries;
        }

    }
}

Вывод с использованием цикла foreach, подобного следующему ...

    foreach (var sec in rankingsBySymbol)
    {
        Console.WriteLine(sec.Key);
        foreach (var secRank in sec)
        {
            Console.WriteLine("  {0} value {1} rank {2}",secRank.Date, secRank.Value, secRank.Rank);
        }
    }

Должно быть следующим ...

6752 JT
  1/15/2011 12:00:00 AM value 30 rank 1
  1/16/2011 12:00:00 AM value 20 rank 2
  1/17/2011 12:00:00 AM value 10 rank 3
6753 JT
  1/15/2011 12:00:00 AM value 20 rank 2
  1/16/2011 12:00:00 AM value 30 rank 1
  1/17/2011 12:00:00 AM value 20 rank 2
  1/18/2011 12:00:00 AM value 30 rank 1
6754 JT
  1/16/2011 12:00:00 AM value 10 rank 3
  1/17/2011 12:00:00 AM value 30 rank 1
  1/18/2011 12:00:00 AM value 30 rank 2

Примечание. В окончательном выводе необязательно указывать начальное значение, используемое для расчета рейтинга, а только дату и рейтинг. Я включил его, потому что это облегчает понимание первоначального вопроса.

1 Ответ

5 голосов
/ 08 марта 2011

Ваши структуры данных не очень понятны, но я думаю вы хотите что-то вроде:

// Initial query just to get a sequence of { Symbol, Date, Value } entries.
var entries = from securityPair in ds.securities
              from valuation in securityPair.Value.timeSeries["liquidity"]
              select new { Symbol = securityPair.Key,
                           Date = valuation.Key,
                           valuation.Value };

// Now do the grouping, sorting and ranking
var groupedByDate = from entry in entries
                    group entry by entry.Date into date
                    select date.OrderByDescending(x => x.Value)
                               .ThenBy(x => x.Symbol)
                               // Use the overload of Select which includes the
                               // index within the sequence (*after* sorting)
                               .Select((x, index) => new {
                                    x.Symbol,
                                    x.Value,
                                    x.Date,
                                    Rank = index + 1,
                                });

// Now group by symbol again
var rankingsBySymbol = groupedByDate.SelectMany(day => day)
                                    .ToLookup(tuple => tuple.Symbol,
                                              tuple => new { tuple.Date,
                                                             tuple.Value,
                                                             tuple.Rank });

Это создаст вам поиск по символу, где каждый символ будет иметь список результатов (в порядке даты) значения символа и ранга на эту дату.

По крайней мере, это план. Я не проверял это вообще ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...