2014-12-11 5 views
2

Есть ли элегантный способ в SAS для вычисления «подсчета отдельных» на нескольких уровнях без использования ряда операторов sql?SAS: Как считать отличным на нескольких уровнях

Предположим, что мы рассчитываем уникальных клиентов. Джо купил 2 больших виджета и 1 маленький виджет, и достаточно просто подсчитать его как 1 клиент для крупных виджетов и 1 клиент для небольших виджетов. Но нам также нужно считать его всего одним «клиентом виджета», поэтому он требует отдельного вычисления SQL. И выясняется, что Джо также купил коврик для мыши, поэтому, когда мы подсчитываем уникальных клиентов для группы «Разное», нам нужен третий расчет SQL. Джо купил все это из магазина №1, но когда мы подсчитываем уникальных клиентов разных продуктов для региона небольшого магазина, мы также должны учитывать покупку Джо чашки кофе из магазина № 2. Другой расчет SQL.

В SAS существует множество способов подсчета вещей, но кажется, что нет простого способа считать «отличные» вещи. Какие-либо предложения?

+1

Надеюсь, что Джо ответит на этот вопрос – mjsqu

+2

Этот вопрос будет полезен для некоторых образцов данных, мне сложно визуализировать. Не могли бы вы добавить свои исходные данные и как вы ожидаете, что это будет выглядеть, когда вы закончите. Для дополнительного кредита добавьте все запрошенные вами запросы. – mjsqu

+0

Спасибо за три ответа ниже (и комментарии от mjsqu). Я намеренно ушел из данных и попытался просто описать ситуацию относительно простым способом. Вам все еще удалось выйти за пределы и обеспечить и очень подробные решения. Все предлагаемые идеи будут полезны в какой-то момент. – Oliver

ответ

4

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

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

data customers; 
    length product $20; 
    input name $ product $ store $ count; 
datalines; 
Joe SmallWidget Store1 1 
Joe LargeWidget Store1 2 
Joe Mousepad Store1 1 
Joe TeaPitcher Store2 1 
Jack SmallWidget Store2 1 
Jack Mousepad Store1 1 
Jane LargeWidget Store2 1 
Jane Mousepad Store1 1 
Jill LargeWidget Store3 1 
;;;; 
run; 

Тогда нам нужно сделать еще одну настройку: определить, как вы собираетесь группировать вещи. Многоканальные форматы позволяют вам запрашивать одно значение для нескольких кодов (т. Е. Большие виджеты и все виджеты). Это один из примеров, здесь вы можете сделать много разных вещей; вы также можете сделать это из набора данных (посмотрите на вариант CNTLIN в формате proc или задайте другой вопрос).

proc format; 
    value $prodgroup (multilabel default=20) 
    SmallWidget = "Small Widgets" 
    SmallWidget = Widgets 
    LargeWidget = "Large Widgets" 
    LargeWidget = Widgets 
    Mousepad = Mousepads 
    Mousepad = "Misc Products" 
    TeaPitcher = "Tea Pitchers" 
    TeaPitcher = "Misc Products" 
    ; 
    value $storeRegions (multilabel) 
    Store1=Store1 
    Store1=West 
    Store2=Store2 
    Store2=East 
    Store3=Store3 
    Store3=East 
    ; 
quit; 

Затем мы сталкиваемся с большой проблемой: SAS сосет при расчете «разных» вещей. На самом деле этого не было сделано. Я не знаю почему; табулировать действительно нужно, но это не так. Тем не менее, это действительно хорошая задача поместить вещи в ведра, и это действительно тяжелая часть здесь; фактический отдельный счетный бит может быть выполнен во втором проходе (который, независимо от вашего начального размера данных, будет очень быстрым, если у вас будет гораздо меньше видов продуктов, чем у вас есть данные).

proc tabulate data=customers out=custdata; 
    class product store /mlf preloadfmt order=data; 
    class name; 
    format product $prodgroup20.; 
    format store $storeRegions6.; 
    tables (all store product store*product),name*n; 
run; 

proc tabulate data=custdata; 
    class product store/missing; 
    tables (product*store), n; 
run; 

MLF PRELOADFMT ORDER=DATA делает MultiLabel битную работу должным образом и делает его выйти в полезном порядке (на мой взгляд). Вы можете добавить NOTSORTED в оператор значения в PROC FORMAT, чтобы получить еще больший контроль, хотя второй PROC TABULATE просто испортит порядок, поэтому я бы не стал беспокоиться.

В этом случае мы сначала создаем таблицу, которая является клиентом, затем эта таблица выводится в набор данных; этот набор данных теперь, как гарантируется, будет содержать одну строку на каждого клиента за [независимо от группировки], если группировки отражаются в обоих procs (за вычетом класса NAME!).

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

proc tabulate data=customers out=custdata2; 
    class product store /mlf preloadfmt order=data; 
    class name; 
    format product $prodgroup20.; 
    format store $storeRegions6.; 
    tables (all store product store*product),name*n/printmiss; 
run; 

proc sql; 
    select product, store, sum(case when n>0 then 1 else 0 end) as count 
    from custdata2 
    group by product,store; 
quit; 

Обратите внимание на одно изменение в строке таблицы: printmiss, который инструктирует Tabulate, чтобы сделать одну линию для каждой возможной комбинации независимо от того, что. Затем SQL выполняет остальную часть работы. Конечно, этот SQL также мог бы повторить второй оператор Tabulate раньше, если вы предпочитаете SQL.

3

Если я интерпретирую это правильно, это звучит так, как средство proc с выражением класса может дать вам то, что вы хотите.

Добавить магазин (1 против 2), продукт (большой виджет, маленький виджет, кофе, & коврик для мыши), сводный продукт (виджет против не-виджета) в качестве классов и посмотрите на частоту появления.

Если кофе Джо появляется несколько раз за ту же покупку, вам может потребоваться предварительно обработать данные с помощью отдельного оператора SQL select.

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

+0

Я обычно предпочитаю 'TABULATE'' для« СРЕДСТВ »для этого, так как он запрашивает частоту (для которой предназначен Tabulate), в то время как средство способно выполнять указанную частоту, это не совсем его цель; и ему нужна числовая переменная, с которой Tabulate может работать без нее. Но средства, безусловно, будут работать (и могут работать с MLF, если данные требуют этого). – Joe

2

Reaaally short on time, поэтому я буду сбрасывать код и запускать ... но я думаю, что это должно сделать трюк. Я использую набор данных sashelp.cars для некоторых выборочных данных. Я собираюсь сказать, что комбинация make + model - это «отличное» значение, которое я хочу измерить как можно большим количеством способов.

Создать образец данных. Флаг - это просто числовое поле, которое мы будем использовать для использования на следующем шаге. Обратите внимание, что в этих данных важно, что если у вас есть поля a, b, c, make + model, то эта комбинация значений должна быть уже уникальной.

data test; 
    length key $50; 
    set sashelp.cars; 
    key = cats(make,model); 
    flag = 1; 
    keep make type origin key flag ; 
run; 

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

proc summary data=test noprint missing; 
    class make type origin key; 
    var flag; 
    output out=smry(where=(mod(_type_,2) eq 1)) sum=; 
run; 

Просто подведите итоговую таблицу и вуаля!

proc sql noprint; 
    create table all_combos as 
    select make, 
     type, 
     origin, 
     sum(flag) as distinct_keys 
    from smry 
    group by 1,2,3,4 
    order by _type_ 
    ; 
quit; 

Я вернусь к этому вопросу и объясню подробнее, как это работает. Если у кого-то еще есть время прямо сейчас, не стесняйтесь редактировать этот пост ;-)

EDIT: Просто прочитайте ответ JJFord, и это в основном реализация этого сообщения.

Смежные вопросы