Хорошо, не очень понятно, что вы ищете, но вы указали, что хотите провести какой-то частотный анализ на основе комбинаций до трех фармацевтических продуктов.
Первый шаг в таком анализе - это взять данные аптеки и для каждого user_id
определить наборы из 1, 2 и 3 drug_dose
комбинаций, в которых они участвуют, поскольку вы, возможно, захотите сделать тот же анализ на substance_name
, drug_name
и / или drug_code
Я собираюсь бросить в него кухонную раковину и сделать все четыре. Не зная, какая у вас база данных, я собираюсь использовать SQL Server 2017 для этого примера, хотя используемые концепции применимы к таким базам данных, как Oracle, MySQL, PostgreSQL и другим, хотя синтаксис может отличаться.
Чтобы создать drug_code
и другие комбинации, я сначала присоединю таблицу pharmacy_data
к таблице drug_reference
, а затем использую рекурсивный запрос к составным данным:
with usage_info as (
select pd.user_id
, dr.drug_code
, dr.drug_name
, dr.substance_name
, concat(dr.substance_name,dr.dosage,dr.unit) drug_dose
from pharmacy_data pd
join drug_reference dr
on dr.drug_code = pd.drug_code
), recur(user_id, combo_id, dc_combo, dc_combo_size, dn_combo, sn_combo, dd_combo, last_dc) as (
-- Anchor part
select user_id
, cast(cast(drug_code as binary(4)) as varbinary(max))
, cast(drug_code as varchar(max))
, 1
, cast(drug_name as varchar(max))
, cast(substance_name as varchar(max))
, cast(drug_dose as varchar(max))
, drug_code
from usage_info
union all
-- Recursive Part
select prev.user_id
, prev.combo_id+cast(curr.drug_code as binary(4))
, prev.dc_combo+','+cast(curr.drug_code as varchar(max))
, prev.dc_combo_size+1
, prev.dn_combo+','+curr.drug_name
, prev.sn_combo+','+curr.substance_name
, prev.dd_combo+','+curr.drug_dose
, curr.drug_code
from recur prev
join usage_info curr
on prev.user_id = curr.user_id
and prev.last_dc < curr.drug_code
and prev.dc_combo_size < 3 -- Maximum combination size
)
Выбор из приведенных выше общих табличных выражений для данных, представленных в вашем вопросе:
select * from recur;
показывает, что некоторые нарушения в группировках для столбцов dn_combo
, sn_combo
и, возможно, dd_combo
, например, существуют dn_combo
s для 'CAZERTA, BEXERA' и 'BEXERA, CAZERTA', которые действительно должны быть эквивалентным
Чтобы исправить это, я нормализую комбинации, разделив их и перекомпоновав в отсортированном порядке. В процессе я также буду дедуплицировать любой экземпляр, в котором user_id может иметь два или более эквивалентных, но не идентичных продукта, например. две разные дозы одного и того же лекарства:
, combos as (
select user_id
, combo_id
, dc_combo
, dc_combo_size
, -- Normalize and deduplicate Drug_Name combos
(select string_agg(value,',') within group (order by value)
from (select distinct value from string_split(dn_combo,',')) dn
) dn_combo
, (select count(distinct value) from string_split(dn_combo,',')) dn_combo_size
, -- Normalize and deduplicate Substance_Name combos
(select string_agg(value,',') within group (order by value)
from (select distinct value from string_split(sn_combo,',')) sn
) sn_combo
, (select count(distinct value) from string_split(sn_combo,',')) sn_combo_size
, -- Normalize and deduplicate Drug_Dose combos
(select string_agg(value,',') within group (order by value)
from (select distinct value from string_split(dd_combo,',')) ddc
) dd_combo
, (select count(distinct value) from string_split(dd_combo,',')) dd_combo_size
from recur
)
Теперь, хотя вы можете просто выбрать count(user_id) over (partition by <grouping_column>)
, чтобы получить частоту встречаемости каждой комбинации лекарств, эти цифры могут быть завышены. Например, если ваши данные имеют дополнительные user_id
из 999 с drug_code
с 50, 100, 200 и 350 (это две разные дозы BEXERA вместе с AXIOM и CAZERTA), то user_id
999 будет отображаться несколько раз для каждой комбинации, которая включает в себя BEXERA. В зависимости от типа вашей базы данных вы можете просто выбрать count(DISTINCT user_id) over (partition by <grouping_column>)
, но с SQL Server 2017 он не позволяет использовать отдельный оператор в аналитических функциях. </shrug>
Мы все еще можем сделать это, просто сделав еще один шаг для определения уникальных значений в группе. Введите Common Table combo2, где мы вычисляем номера строк в разных разделах:
, combo2 as (
select user_id
, combo_id
, dc_combo
, dc_combo_size
, row_number() over (partition by dc_combo, user_id order by dc_combo) dc_uid_rn
, dn_combo
, dn_combo_size
, row_number() over (partition by dn_combo, user_id order by dc_combo) dn_uid_rn
, row_number() over (partition by dn_combo, dc_combo order by user_id) dn_combo_rn
, sn_combo
, sn_combo_size
, row_number() over (partition by sn_combo, user_id order by dc_combo) sn_uid_rn
, row_number() over (partition by sn_combo, dc_combo order by user_id) sn_combo_rn
, dd_combo
, dd_combo_size
, row_number() over (partition by dd_combo, user_id order by dc_combo) dd_uid_rn
, row_number() over (partition by dd_combo, dc_combo order by user_id) dd_combo_rn
from combos
)
И, наконец, вычислим количество, которых у нас есть два типа. Столбцы uid_cnt
представляют собой количество различных user_id
с для каждой комбинации, а столбцы combo_cnt
указывают количество различных комбинаций drug_code, составляющих менее гранулированные группировки:
select user_id
, combo_id
, dc_combo
, dc_combo_size
, count(case dc_uid_rn when 1 then 1 end) over (partition by dc_combo) dc_uid_cnt
, dn_combo
, dn_combo_size
, count(case dn_uid_rn when 1 then 1 end) over (partition by dn_combo) dn_uid_cnt
, count(case dn_combo_rn when 1 then 1 end) over (partition by dn_combo) dn_combo_cnt
, sn_combo
, sn_combo_size
, count(case sn_uid_rn when 1 then 1 end) over (partition by sn_combo) sn_uid_cnt
, count(case sn_combo_rn when 1 then 1 end) over (partition by sn_combo) sn_combo_cnt
, dd_combo
, dd_combo_size
, count(case dd_uid_rn when 1 then 1 end) over (partition by dd_combo) dd_uid_cnt
, count(case dd_combo_rn when 1 then 1 end) over (partition by dd_combo) dd_combo_cnt
from combo2
order by dn_combo, dd_combo
Все вместе с моими дополнительными образцами данных приведенный выше код приводит к следующей таблице . Чтобы увидеть его в действии, см. SQL Fiddle :
| user_id | dc_combo | dc_combo_size | dc_uid_cnt | dn_combo | dn_combo_size | dn_uid_cnt | dn_combo_cnt | sn_combo | sn_combo_size | sn_uid_cnt | sn_combo_cnt | dd_combo | dd_combo_size | dd_uid_cnt | dd_combo_cnt |
|---------|-------------|---------------|------------|----------------------|---------------|------------|--------------|---------------------------------|---------------|------------|--------------|-------------------------------------------------|---------------|------------|--------------|
| 3 | 200 | 1 | 2 | AXIOM | 1 | 4 | 3 | nsaid | 1 | 4 | 3 | nsaid10mg | 1 | 2 | 1 |
| 999 | 200 | 1 | 2 | AXIOM | 1 | 4 | 3 | nsaid | 1 | 4 | 3 | nsaid10mg | 1 | 2 | 1 |
| 175 | 300 | 1 | 1 | AXIOM | 1 | 4 | 3 | nsaid | 1 | 4 | 3 | nsaid25mg | 1 | 1 | 1 |
| 1 | 25 | 1 | 1 | AXIOM | 1 | 4 | 3 | nsaid | 1 | 4 | 3 | nsaid5mg | 1 | 1 | 1 |
| 999 | 200,350 | 2 | 1 | AXIOM,BEXERA | 2 | 3 | 5 | nsaid,potassium | 2 | 3 | 5 | nsaid10mg,potassium12mg | 2 | 1 | 1 |
| 999 | 50,200,350 | 3 | 1 | AXIOM,BEXERA | 2 | 3 | 5 | nsaid,potassium | 2 | 3 | 5 | nsaid10mg,potassium12mg,potassium20mg | 3 | 1 | 1 |
| 999 | 50,200 | 2 | 1 | AXIOM,BEXERA | 2 | 3 | 5 | nsaid,potassium | 2 | 3 | 5 | nsaid10mg,potassium20mg | 2 | 1 | 1 |
| 175 | 50,300 | 2 | 1 | AXIOM,BEXERA | 2 | 3 | 5 | nsaid,potassium | 2 | 3 | 5 | nsaid25mg,potassium20mg | 2 | 1 | 1 |
| 1 | 25,50 | 2 | 1 | AXIOM,BEXERA | 2 | 3 | 5 | nsaid,potassium | 2 | 3 | 5 | nsaid5mg,potassium20mg | 2 | 1 | 1 |
| 999 | 100,200,350 | 3 | 1 | AXIOM,BEXERA,CAZERTA | 3 | 2 | 3 | nsaid,potassium,sodium chloride | 3 | 2 | 3 | nsaid10mg,potassium12mg,sodium chloride10mg | 3 | 1 | 1 |
| 999 | 50,100,200 | 3 | 1 | AXIOM,BEXERA,CAZERTA | 3 | 2 | 3 | nsaid,potassium,sodium chloride | 3 | 2 | 3 | nsaid10mg,potassium20mg,sodium chloride10mg | 3 | 1 | 1 |
| 1 | 25,50,100 | 3 | 1 | AXIOM,BEXERA,CAZERTA | 3 | 2 | 3 | nsaid,potassium,sodium chloride | 3 | 2 | 3 | nsaid5mg,potassium20mg,sodium chloride10mg | 3 | 1 | 1 |
| 999 | 100,200 | 2 | 1 | AXIOM,CAZERTA | 2 | 2 | 2 | nsaid,sodium chloride | 2 | 2 | 2 | nsaid10mg,sodium chloride10mg | 2 | 1 | 1 |
| 1 | 25,100 | 2 | 1 | AXIOM,CAZERTA | 2 | 2 | 2 | nsaid,sodium chloride | 2 | 2 | 2 | nsaid5mg,sodium chloride10mg | 2 | 1 | 1 |
| 201 | 350 | 1 | 2 | BEXERA | 1 | 5 | 4 | potassium | 1 | 5 | 4 | potassium12mg | 1 | 2 | 1 |
| 999 | 350 | 1 | 2 | BEXERA | 1 | 5 | 4 | potassium | 1 | 5 | 4 | potassium12mg | 1 | 2 | 1 |
| 999 | 50,350 | 2 | 1 | BEXERA | 1 | 5 | 4 | potassium | 1 | 5 | 4 | potassium12mg,potassium20mg | 2 | 1 | 1 |
| 378 | 400 | 1 | 1 | BEXERA | 1 | 5 | 4 | potassium | 1 | 5 | 4 | potassium15mg | 1 | 1 | 1 |
| 1 | 50 | 1 | 3 | BEXERA | 1 | 5 | 4 | potassium | 1 | 5 | 4 | potassium20mg | 1 | 3 | 1 |
| 175 | 50 | 1 | 3 | BEXERA | 1 | 5 | 4 | potassium | 1 | 5 | 4 | potassium20mg | 1 | 3 | 1 |
| 999 | 50 | 1 | 3 | BEXERA | 1 | 5 | 4 | potassium | 1 | 5 | 4 | potassium20mg | 1 | 3 | 1 |
| 999 | 50,100,350 | 3 | 1 | BEXERA,CAZERTA | 2 | 4 | 5 | potassium,sodium chloride | 2 | 4 | 5 | potassium12mg,potassium20mg,sodium chloride10mg | 3 | 1 | 1 |
| 999 | 100,350 | 2 | 1 | BEXERA,CAZERTA | 2 | 4 | 5 | potassium,sodium chloride | 2 | 4 | 5 | potassium12mg,sodium chloride10mg | 2 | 1 | 1 |
| 201 | 350,450 | 2 | 1 | BEXERA,CAZERTA | 2 | 4 | 5 | potassium,sodium chloride | 2 | 4 | 5 | potassium12mg,sodium chloride30mg | 2 | 1 | 1 |
| 378 | 100,400 | 2 | 1 | BEXERA,CAZERTA | 2 | 4 | 5 | potassium,sodium chloride | 2 | 4 | 5 | potassium15mg,sodium chloride10mg | 2 | 1 | 1 |
| 1 | 50,100 | 2 | 2 | BEXERA,CAZERTA | 2 | 4 | 5 | potassium,sodium chloride | 2 | 4 | 5 | potassium20mg,sodium chloride10mg | 2 | 2 | 1 |
| 999 | 50,100 | 2 | 2 | BEXERA,CAZERTA | 2 | 4 | 5 | potassium,sodium chloride | 2 | 4 | 5 | potassium20mg,sodium chloride10mg | 2 | 2 | 1 |
| 1 | 100 | 1 | 3 | CAZERTA | 1 | 4 | 2 | sodium chloride | 1 | 4 | 2 | sodium chloride10mg | 1 | 3 | 1 |
| 378 | 100 | 1 | 3 | CAZERTA | 1 | 4 | 2 | sodium chloride | 1 | 4 | 2 | sodium chloride10mg | 1 | 3 | 1 |
| 999 | 100 | 1 | 3 | CAZERTA | 1 | 4 | 2 | sodium chloride | 1 | 4 | 2 | sodium chloride10mg | 1 | 3 | 1 |
| 201 | 450 | 1 | 1 | CAZERTA | 1 | 4 | 2 | sodium chloride | 1 | 4 | 2 | sodium chloride30mg | 1 | 1 | 1 |