green_fr (green_fr) wrote,
green_fr
green_fr

Category:

Formation SAS

Побывал ещё на одних курсах по SAS.

Общее впечатление от языка развивается по двум направлениям.
Первое: ну и наворотили, система-монстр, может всё.
Второе: надо всё-таки иногда брать смелость и переписывать всё с нуля.


Как я узнал ещё на прошлых курсах, в языке SAS есть две фазы: компиляция и исполнение.
Возьмём, например, следующий код (нумерация линий добавлена мной):
data Subset;                                 (1)
  do PickIt = 100 to TotObs by 100;          (2)
    set Sales point = PickIt nobs = TotObs;  (3)
    output;                                  (4)
  end;
  stop;
run;

Эта программа копирует часть таблицы Sales в таблицу Subset. Точнее - каждую сотую строчку.
Как она это делает? Очень просто. Команда (3) позиционирует таблицу Sales на нужной строчке, затем команда (4) копирует строчку в стандартный выход, который определён командой (1) как таблица Subset.
Вызывает вопрос лишь верхняя граница цикла команды (2) - TotObs. Это на самом деле переменная, определённая командой (3) - ключевое слово nobs резервирует переменную и присваивает ей значение количества строчек в таблице.
И в тот момент, когда изумлённая публика задаётся вопросом: в каком же порядке исполняются эти команды, преподаватель говорит, что сначала исполняется команда (3) на уровне компиляции, определяя переменные, затем - на уровне исполнения - команды исполняются как им положено.
На вопрос, откуда же в момент компиляции SAS знает количество строчек в не читанной ещё таблице, ответ - из header этой таблицы, который содержит в себе подобную статистику.

Другой пример из той же серии - огромный кусок кода, обрамлённый if 0 then ... end, который, понятное дело, не исполняется никогда. Нужен исключительно для фазы компиляции. Команды (никому не нужные! они ни при каких обстоятельствах не будут исполнены!) подбираются так, чтобы, глядя на них, компилятор сделал то, что хочет пользователь.


Красивый алгоритм (я не знал) случайной выборки n уникальных элементов из множества N элементов.
Пробегаем все N элементов.
Если случайное число от 0 до 1 меньше, чем количество элементов, которое нам осталось найти / количество оставшихся ещё не просмотренными элементов, то мы берём текущий элемент.
Переходим к следующему элементу.
Каким-то чудом (читай: мне не очевидно) распределение получается равновероятным.


Оригинальная реализация join в SAS. Предположим, есть у нас 2 таблицы, между ними связь по некоему ключу, некоторому значению которого соответствует 3 записи в первой таблице (назовём из X1, X2 и X3) и две записи во второй (Y1 и Y2). "Интуитивно понятный" (после 10 лет работы с SQL) join должен выдать 6 строчек, соответствующих комбинациям X1Y1, X1Y2, X2Y1, X2Y2, X3Y1 и X3Y2. SAS выдаёт 3 строчки: X1Y1, X2Y2 и X3-- - последняя похожа на выход outer join, когда не найдено соответствия во второй таблице.

Сколько угодно преп может повторять, что оба варианта (в SAS есть и SQL) одинаково правильные, и что нужно выбирать наиболее подходящий. Мне это всё равно будет казаться багом первых версий, вошедшим в документацию, потому что было поздно уже исправлять.

При этом приводится вариант для тех, кто хочет "нормальный" join, но не знает SQL. Два вложенных цикла, один if. Название курсов - best practice и оптимизация кода.


А это уже alekro dedicated (Шурик в институте написал СУБД, хранившую данные в куче текстовых файлов, и понимавшую даже какие-то начала SQL).
data Euros;
  set Dollars;
    do while (not (StartDate le OpDate le EndDate));
      set Rates;
    end;
  EurosAmount = DollarsAmount / Rate;
run;

Два вложенных цикла. Первый пробегает по табличке с долларовыми ценами, второй - по табличке курсов доллара. Когда находим нужный нам курс (дата операции попадает в период действия курса), используем эти данные.
Всё это из-за того, что родной синтаксис join пишется не в виде Table1.Field1 {operator} Table2.Field2, а by Field. Оператор по определению "равенство", имя поля должно быть одинаковым в обеих таблицах.

Аналогичный пример для включения агрегационных функций. Цикл по всем строчкам таблицы, if первая строчка, пробежать отдельно ту же самую таблицу, чтобы посчитать все нужные агрегаты.

Повторяю: курс был про best practice.
Вообще, поражает смесь уровней в SAS. С одной стороны - язык для чайников (с точки зрения программирования). С другой стороны - без тонкого знания о том, как работают индексы, невозможно использовать некоторую функциональность. При том, что по мне - само знание языка о том, что есть какие-то индексы является лишним. Язык программирования и администрирования должны быть максимально разнесены. Мне кажется, программа должна работать одинаково (за вычетом времени исполнения) в оптимизированной и не оптимизированной базе.


Преп объясняет про длину (в байтах) численной переменной, нужно оптимизировать, но не увлекаться. Потому что SAS не знает такой ошибки как "значение слишком велико для переменной". Все числа - с плавающей точкой, если что не так - "округляет".
Интуитивно понятная демонстрация: переменная, хранящая без потерь целые числа до 8192. Присваиваем ей 111111 - округление до 111104. Немая сцена.
Резюме слушателей: ну его к лешему трогать размер численных переменных!
Tags: rabota, sas
Subscribe

  • Pour la science №524

    Короткая заметка про хищные грибы :-) Точнее даже, пишут о том, что такие грибы известны давно: они могут на несколько часов парализовать мелких…

  • Pour la Science №523

    Заметка о том, что археологи, раскапывая стоянки древних инуитов на Аляске, нашли венецианское стекло. Точнее бусинки, надетые на ниточку. Ниточка…

  • Pour la science №522

    Я наконец-то понял / смог представить себе проекцию 4-мерного куба (то, что получилось на  Большой арке Дефанс) и развёртку 4-мерного куба (то, что…

  • Post a new comment

    Error

    default userpic

    Your reply will be screened

    Your IP address will be recorded 

    When you submit the form an invisible reCAPTCHA check will be performed.
    You must follow the Privacy Policy and Google Terms of use.
  • 10 comments

  • Pour la science №524

    Короткая заметка про хищные грибы :-) Точнее даже, пишут о том, что такие грибы известны давно: они могут на несколько часов парализовать мелких…

  • Pour la Science №523

    Заметка о том, что археологи, раскапывая стоянки древних инуитов на Аляске, нашли венецианское стекло. Точнее бусинки, надетые на ниточку. Ниточка…

  • Pour la science №522

    Я наконец-то понял / смог представить себе проекцию 4-мерного куба (то, что получилось на  Большой арке Дефанс) и развёртку 4-мерного куба (то, что…