SAS-разделить набор данных на основе значений в столбце (символе), а затем дополнительно разделить каждый из этих наборов данных на основе столбца времени

У меня есть данные о торговле акциями за день - около 60 миллионов строк. По сути, я хочу создать набор данных, в котором указана средняя продолжительность каждого 5-минутного интервала для каждой из акций.

Исходный набор данных

Наблюдения время символ торговая цена идентификатор сделки дата-время продолжительность 1 093000154451968 А 152,24 7.1675Е13 1943170200,2 . 2 093000845296640 А 151,99 5.2984Е13 1943170200,8 0,69084 3 093000845296640 А 151,99 5.2984Е13 1943170200,8 0.00000 4 093000846918400 А 151,99 5.2984Е13 1943170200,8 0,00162 5 093000847665152 А 151,94 6.2879E13 1943170200,8 0,00075 6 093000847675136 А 151,94 6.2879E13 1943170200,8 0,00001 7 093000857328128 А 151,94 5.2984Е13 1943170200,9 0,00965 8 093000889283840 А 151,24 7.1675Е13 1943170200,9 0,03196 9 093001249114624 А 151,74 7.1675Е13 1943170201.2 0,35983 10 093001824934912 А 151,99 7.1675Е13 1943170201,8 0,57582 11 093001834587904 А 151,71 5.2989E13 1943170201,8 0,00965 12 093002261742336 А 151,99 7.1675Е13 1943170202.3 0,42715

Здесь переменная «время» настроена как hhmmssnnnnnnnnn (n указывает наносекунды, т.е. секунды считаются для 9 значащих цифр после запятой) и переменная datetime преобразуется в наносекунды с использованием даты и времени. Для этого кода я работаю только с данными за один день, поэтому использую только переменную «время».

Конечный результат

Запас Временной интервал Средняя продолжительность А 09:30-09:35 23456 А 09:35-09:40 56789 А ........ ...... А 1555-1600 57689 Б 09:30-09:35 23456 Б 09:35-09:40 56789 Б ........ ...... Б 1555-1600 57689 .. ... ... Z 09:30-09:35 23456 Z 09:35-09:40 56789 Z ........ ...... Z 1555-1600 57689

Шаг 1:

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

Шаг 2:

Чтобы суммировать значения в столбце для каждого 5-минутного интервала с 09:30 до 16:00. Я борюсь здесь.

Текущий код:

/* Read Dataset */
   DATA working_dataset;
   set "C:\EQY_US_ALL_TRADE_202107\test_sample_sorted";
   run;

/* List of Unique Symbols and feed them into new variables */
   proc sql noprint;
   select distinct symbol into :symbol1 - (NOTRIM)
   from working_dataset;
   %put &symbol1;
   %put &symbol2;

/* Count of Unique Symbols and store the value in variable "n" */
   proc sql noprint;
   select count(distinct symbol) into: n
   from working_dataset;
   %put &n;

/* Keeping the variables needed for the analysis */
   DATA working_dataset_2;
   SET working_dataset (keep = symbol time duration tradePrice datetime tradeId);
   run;


/* Extracting stock symbol names from the dataset;*/

    proc sort data=working_dataset_2 out=symblist (keep = symbol)
    nodupkey;
    by symbol;
    run;

/* Creating multiple datasets from the parent dataset;*/
    data _null_;
    set symblist;
    call execute('data ' !! compress(symbol) !! '; set working_dataset_2; where symbol = "' !! symbol !! '"; run;');
    run;

Для шага 2:

Я не знаю, как это сделать, но я планирую запустить цикл для 78x 5-минутных интервалов между 09:30 и 16:00, используя оператор if, управляемый значением цикла. Следующее - просто принятие желаемого за действительное, а не код. Я не знаю, с чего начать.

data dataset_final;
set "A"; /* To be changed as per variable for stock symbol */
array symb(&n); /* this array should have all the stock symbols */
do over; /* do over for all the array items in the array symb(&n) */
do i = 1 to 78;
if (time GE (093000000000000 + &i.- 1)) & (time LT (093000000000000 + &i.))
then send obs to symb_j_0930+&i.-1
end;

Любая помощь приветствуется. Я не знаю, как прикрепить файл данных.

Шаг 1 работает. Я могу создавать разные наборы данных, используя и вызывая/выполняя.

Лог для шага 1:

439
440  DATA working_dataset;
441  set "C:\EQY_US_ALL_TRADE_202107\test_sample_sorted";
442  run;

NOTE: There were 50000 observations read from the data set
      C:\EQY_US_ALL_TRADE_202107\test_sample_sorted.
NOTE: The data set WORK.WORKING_DATASET has 50000 observations and 25 variables.
NOTE: DATA statement used (Total process time):
      real time           0.12 seconds
      cpu time            0.09 seconds


443
444  proc sql noprint;
445  select distinct symbol into :symbol1 - (NOTRIM)
                                            -
                                            22
                                            76
ERROR 22-322: Syntax error, expecting one of the following: ',', :, FROM, NOTRIM.

ERROR 76-322: Syntax error, statement will be ignored.

446  from working_dataset;
447  %put &symbol1;
A
448  %put &symbol2;
AA
449
NOTE: The SAS System stopped processing this step because of errors.
NOTE: PROCEDURE SQL used (Total process time):
      real time           0.03 seconds
      cpu time            0.01 seconds



450  proc sql noprint;
451  select count(distinct symbol) into: n
452  from working_dataset;
453  %put &n;
2
454
NOTE: PROCEDURE SQL used (Total process time):
      real time           0.04 seconds
      cpu time            0.04 seconds


455  DATA working_dataset_2;
456  SET working_dataset (keep = symbol time duration tradePrice datetime tradeId);
457
458  /* Extracting stock symbol names from the dataset;*/

NOTE: There were 50000 observations read from the data set WORK.WORKING_DATASET.
NOTE: The data set WORK.WORKING_DATASET_2 has 50000 observations and 6 variables.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds


459  proc sort data=working_dataset_2 out=symblist (keep = symbol)
460  nodupkey;
461  by symbol;
462  run;

NOTE: There were 50000 observations read from the data set WORK.WORKING_DATASET_2.
NOTE: 49998 observations with duplicate key values were deleted.
NOTE: The data set WORK.SYMBLIST has 2 observations and 1 variables.
NOTE: PROCEDURE SORT used (Total process time):
      real time           0.03 seconds
      cpu time            0.01 seconds


463  /* Creating multiple datasets from the parent dataset;*/
464  data _null_;
465  set symblist;
466  call execute('data ' !! compress(symbol) !! '; set working_dataset_2; where symbol = "' !! symbol
466!  !! '"; run;');
467  run;

NOTE: There were 2 observations read from the data set WORK.SYMBLIST.
NOTE: DATA statement used (Total process time):
      real time           0.00 seconds
      cpu time            0.00 seconds


NOTE: CALL EXECUTE generated line.
1   + data A; set working_dataset_2; where symbol = "A                "; run;

NOTE: There were 24304 observations read from the data set WORK.WORKING_DATASET_2.
      WHERE symbol='A                ';
NOTE: The data set WORK.A has 24304 observations and 6 variables.
NOTE: DATA statement used (Total process time):
      real time           0.01 seconds
      cpu time            0.01 seconds


2   + data AA; set working_dataset_2; where symbol = "AA               "; run;

NOTE: There were 25696 observations read from the data set WORK.WORKING_DATASET_2.
      WHERE symbol='AA               ';
NOTE: The data set WORK.AA has 25696 observations and 6 variables.
NOTE: DATA statement used (Total process time):
      real time           0.02 seconds
      cpu time            0.01 seconds

Шаг 2, где я ужасно борюсь. Я не уверен, как сделать код.

Я не понимаю, зачем нужен цикл. Не похоже, что ваши временные интервалы перекрываются, почему бы просто не преобразовать значения в начало интервала или не использовать формат, чтобы вы могли просто группировать по интервалу без какого-либо цикла?

Tom 27.12.2022 00:01

Почему вы называете СУММУ СРЕДНИМ? Какой расчет на самом деле пытаются сделать? Найдите сумму или среднее?

Tom 27.12.2022 00:08

@Tom - я могу ошибаться, используя цикл. Что я пытаюсь сделать, так это сказать, что для акции "А" есть 6 сделок (со значениями "длительности" - 4,6,7,12,3,6) в 5-минутном интервале 09:35 - 09:40. Мне нужен окончательный набор данных. иметь соответствующую запись Акции «А», временной интервал «09:35-09:40» и среднюю продолжительность, которая рассчитывается как (4+6+7+12+3+6)/6 = 38/6 = 6,33. Это необходимо повторить для всех 5-минутных интервалов и всех акций.

Vir Gandhi 27.12.2022 03:32

Итак, вам нужно СРЕДНЕЕ значение значений, а не СУММА значений.

Tom 27.12.2022 05:21
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
4
64
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы говорите, что испытываете затруднения при выполнении шага 2: «Суммировать значения в столбце для каждого 5-минутного интервала с 09:30 до 16:00. Здесь у меня проблемы».

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

data final;
  set <dataset>;
  time_interval = intck("minute", "09:30:00", tradetime);
  time_interval = time_interval - mod(time_interval, 5);
run;

proc sql;
    select stock, time_interval, avg(duration) as avg_duration
    from final
    group by stock, time_interval;
quit;

Но если вы хотите хранить несколько наборов данных по запасам, просто удалите переменную «запас» из кода и примените ее к каждому имеющемуся у вас набору данных запасов.

Спасибо @linstar. Ваш подход кажется намного умнее, чем я думал. Я попробую этот код и дам вам обратную связь.

Vir Gandhi 27.12.2022 05:51

Оба решения работают. Стек по какой-то причине не позволяет им обоим быть принятыми.

Vir Gandhi 27.12.2022 07:27

НП, рад, что это сработало!

linstar 27.12.2022 22:54
Ответ принят как подходящий

Предполагая, что у вас есть фактическое значение времени (вы можете создать его из своей первой 16-значной строки), вы можете просто преобразовать это время в начало 5-минутного интервала и использовать его для группировки данных. Нет необходимости в цикле (или разделении).

Давайте изменим данные вашего примера, чтобы они фактически содержали более одного символа акций и более одного временного интервала. Вы можете преобразовать первые 6 символов строки TIME в фактическое значение TIME. Который мы затем можем преобразовать в начало 5-минутного интервала.

data have ;
  input time :$16. symbol :$4. tradePrice tradeId datatime duration;
  tod = input(time,hhmmss6.);
  interval='00:05:00't*int(tod/'00:05:00't);
  format tod interval tod8.;
  nanosec = input(substr(time,7),32.);
cards;
093000154451968 A 152.24 7.1675E13 1943170200.2 .
093000845296640 A 151.99 5.2984E13 1943170200.8 0.69084
093500845296640 A 151.99 5.2984E13 1943170200.8 0.00000
093500846918400 A 151.99 5.2984E13 1943170200.8 0.00162
093800847665152 A 151.94 6.2879E13 1943170200.8 0.00075
093000847675136 B 151.94 6.2879E13 1943170200.8 0.00001
093100857328128 B 151.94 5.2984E13 1943170200.9 0.00965
093900889283840 B 151.24 7.1675E13 1943170200.9 0.03196
093001249114624 C 151.74 7.1675E13 1943170201.2 0.35983
093301824934912 C 151.99 7.1675E13 1943170201.8 0.57582
093801834587904 C 151.71 5.2989E13 1943170201.8 0.00965
094102261742336 C 151.99 7.1675E13 1943170202.3 0.42715
;

Таким образом, когда у вас есть набор данных (или даже представление) с тремя необходимыми переменными, ИНТЕРВАЛ СИМВОЛА и ПРОДОЛЖИТЕЛЬНОСТЬ, вы можете просто использовать СУММАРНУЮ ПРОЦЕССОР для получения среднего значения длительности.

proc summary nway ;
  class symbol interval;
  var duration;
  output out=want mean=mean_duration ;
run;

Полученные результаты:

                                                   mean_
Obs    symbol    interval    _TYPE_    _FREQ_    duration

 1       A       09:30:00       3         2       0.69084
 2       A       09:35:00       3         3       0.00079
 3       B       09:30:00       3         2       0.00483
 4       B       09:35:00       3         1       0.03196
 5       C       09:30:00       3         2       0.46783
 6       C       09:35:00       3         1       0.00965
 7       C       09:40:00       3         1       0.42715

Спасибо. Это умный взгляд на мою проблему. Я сделаю код и передам вам свой отзыв. Это похоже на очень низкую загрузку процессора. Еще раз спасибо!

Vir Gandhi 27.12.2022 05:54

Это прекрасно работает. Мне не нужно будет создавать отдельные наборы данных, и это очень быстро. Спасибо!

Vir Gandhi 27.12.2022 07:26

Вы также можете создать формат, который группирует данные по интервалам. Затем вы можете работать с существующим набором данных, не создавая новую переменную.

Tom 27.12.2022 19:13

Другие вопросы по теме