У меня есть данные о торговле акциями за день - около 60 миллионов строк. По сути, я хочу создать набор данных, в котором указана средняя продолжительность каждого 5-минутного интервала для каждой из акций.
Исходный набор данных
Здесь переменная «время» настроена как hhmmssnnnnnnnnn
(n указывает наносекунды, т.е. секунды считаются для 9 значащих цифр после запятой)
и переменная datetime преобразуется в наносекунды с использованием даты и времени.
Для этого кода я работаю только с данными за один день, поэтому использую только переменную «время».
Конечный результат
Шаг 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 - я могу ошибаться, используя цикл. Что я пытаюсь сделать, так это сказать, что для акции "А" есть 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-минутных интервалов и всех акций.
Итак, вам нужно СРЕДНЕЕ значение значений, а не СУММА значений.
Вы говорите, что испытываете затруднения при выполнении шага 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. Ваш подход кажется намного умнее, чем я думал. Я попробую этот код и дам вам обратную связь.
Оба решения работают. Стек по какой-то причине не позволяет им обоим быть принятыми.
НП, рад, что это сработало!
Предполагая, что у вас есть фактическое значение времени (вы можете создать его из своей первой 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
Спасибо. Это умный взгляд на мою проблему. Я сделаю код и передам вам свой отзыв. Это похоже на очень низкую загрузку процессора. Еще раз спасибо!
Это прекрасно работает. Мне не нужно будет создавать отдельные наборы данных, и это очень быстро. Спасибо!
Вы также можете создать формат, который группирует данные по интервалам. Затем вы можете работать с существующим набором данных, не создавая новую переменную.
Я не понимаю, зачем нужен цикл. Не похоже, что ваши временные интервалы перекрываются, почему бы просто не преобразовать значения в начало интервала или не использовать формат, чтобы вы могли просто группировать по интервалу без какого-либо цикла?