ntile()
ウィンドウ関数を使用する場合の主な問題は、実際の値に関係なく、ほぼ等しい部分に任意にグループ化されることです。
たとえば、次のクエリの場合:
_select
id,title,price,
row_number() over(order by price) as row_number,
rank() over(order by price) as rank,
count(*) over(order by price) as count,
dense_rank() over(order by price) as dense_rank,
ntile(10) over(order by price) as decile
from paintings
order by price;
_
サイズがほぼ同じ10個のグループを取得します。同じ価格の絵画が最終的に別のビンに入れられる可能性が非常に高くなります。
例えば:
_┌────┬────────────────────────────────────────────┬───────┬────────────┬──────┬───────┬────────────┬────────┐
│ id │ title │ price │ row_number │ rank │ count │ dense_rank │ decile │
╞════╪════════════════════════════════════════════╪═══════╪════════════╪══════╪═══════╪════════════╪════════╡
│ 11 │ Eyes in the Heat │ 10 │ 1 │ 1 │ 1 │ 1 │ 1 │
│ 19 │ Deux fillettes, fond jaune et rouge │ 11 │ 2 │ 2 │ 2 │ 2 │ 1 │
│ 17 │ Flowers in a Pitcher │ 12 │ 3 │ 3 │ 6 │ 3 │ 1 │
│ 5 │ Composition with Red, Yellow and Blue │ 12 │ 4 │ 3 │ 6 │ 3 │ 2 │
│ 18 │ La lecon de musique (The Music Lesson) │ 12 │ 5 │ 3 │ 6 │ 3 │ 2 │
│ 9 │ The Adoration of the Magi │ 12 │ 6 │ 3 │ 6 │ 3 │ 2 │
│ 29 │ Self-Portrait │ 14 │ 7 │ 7 │ 10 │ 4 │ 3 │
│ 25 │ Symphony in White, No. 1: The White Girl │ 14 │ 8 │ 7 │ 10 │ 4 │ 3 │
│ 30 │ The Anatomy Lecture of Dr. Nicolaes Tulp │ 14 │ 9 │ 7 │ 10 │ 4 │ 3 │
│ 20 │ Les repasseuses (Women Ironing) │ 14 │ 10 │ 7 │ 10 │ 4 │ 4 │
│ 1 │ The Birth of Venus │ 15 │ 11 │ 11 │ 14 │ 5 │ 4 │
│ 12 │ Femme se promenant dans une foret exotique │ 15 │ 12 │ 11 │ 14 │ 5 │ 4 │
│ 24 │ Portrait of the Painter’s Mother │ 15 │ 13 │ 11 │ 14 │ 5 │ 5 │
│ 28 │ Jeunes filles au piano │ 15 │ 14 │ 11 │ 14 │ 5 │ 5 │
│ 7 │ Portrait de l artiste (Self-portrait) │ 16 │ 15 │ 15 │ 17 │ 6 │ 5 │
│ 3 │ The Last Supper │ 16 │ 16 │ 15 │ 17 │ 6 │ 6 │
│ 13 │ Combat of a Tiger and a Buffalo │ 16 │ 17 │ 15 │ 17 │ 6 │ 6 │
│ 4 │ The Creation of Man │ 17 │ 18 │ 18 │ 19 │ 7 │ 6 │
│ 22 │ Le Chemin de Fer │ 17 │ 19 │ 18 │ 19 │ 7 │ 7 │
│ 6 │ Femmes de Tahiti [Sur la plage] │ 18 │ 20 │ 20 │ 24 │ 8 │ 7 │
│ 21 │ Le Bar aux Folies-Berg │ 18 │ 21 │ 20 │ 24 │ 8 │ 7 │
│ 26 │ Lady at the Piano │ 18 │ 22 │ 20 │ 24 │ 8 │ 8 │
│ 15 │ Remembrance of a Garden │ 18 │ 23 │ 20 │ 24 │ 8 │ 8 │
│ 16 │ 1914 │ 18 │ 24 │ 20 │ 24 │ 8 │ 8 │
│ 14 │ Ancient Sound, Abstract on Black │ 19 │ 25 │ 25 │ 28 │ 9 │ 9 │
│ 8 │ The Large Turf │ 19 │ 26 │ 25 │ 28 │ 9 │ 9 │
│ 23 │ On the Beach │ 19 │ 27 │ 25 │ 28 │ 9 │ 9 │
│ 2 │ Portrait of Mona Lisa │ 19 │ 28 │ 25 │ 28 │ 9 │ 10 │
│ 27 │ On the Terrace │ 20 │ 29 │ 29 │ 30 │ 10 │ 10 │
│ 10 │ The She-Wolf │ 20 │ 30 │ 29 │ 30 │ 10 │ 10 │
└────┴────────────────────────────────────────────┴───────┴────────────┴──────┴───────┴────────────┴────────┘
_
価格が_12
_のアイテムが4つあるが、2つは十分位数1にあり、2つは十分位2にあることに注意してください。これらのアイテムをまとめておきたいのですが、どの十分位数に悩んでいません。
比較を行うために他のウィンドウ関数を含めました。
ntile()
はrow_number()
のみを使用し、それを基準にカットオフを行っているようです。 rank()
関数またはcount(*)
関数のいずれかを使用した場合、同じ価格のアイテムは同じビンに入れられるため、より公平になります。
これは、PostgreSQLとSQL Serverの両方の動作で、おそらく残りの動作です。
問題は、これを達成する方法はありますか?
rank()
を使用して、各ビンの行数で整数除算を行うことができます。
declare @T table(id int, title varchar(100), price int);
insert into @T(id, title, price) values
(19, 'Deux fillettes, fond jaune et rouge ', 11),
(17, 'Flowers in a Pitcher ', 12),
(5 , 'Composition with Red, Yellow and Blue ', 12),
(18, 'La lecon de musique (The Music Lesson) ', 12),
(9 , 'The Adoration of the Magi ', 12),
(29, 'Self-Portrait ', 14),
(25, 'Symphony in White, No. 1: The White Girl ', 14),
(30, 'The Anatomy Lecture of Dr. Nicolaes Tulp ', 14),
(20, 'Les repasseuses (Women Ironing) ', 14),
(1 , 'The Birth of Venus ', 15),
(12, 'Femme se promenant dans une foret exotique ', 15),
(24, 'Portrait of the Painter’s Mother ', 15),
(28, 'Jeunes filles au piano ', 15),
(7 , 'Portrait de l artiste (Self-portrait) ', 16),
(3 , 'The Last Supper ', 16),
(13, 'Combat of a Tiger and a Buffalo ', 16),
(4 , 'The Creation of Man ', 17),
(22, 'Le Chemin de Fer ', 17),
(6 , 'Femmes de Tahiti [Sur la plage] ', 18),
(21, 'Le Bar aux Folies-Berg ', 18),
(26, 'Lady at the Piano ', 18),
(15, 'Remembrance of a Garden ', 18),
(16, '1914 ', 18),
(14, 'Ancient Sound, Abstract on Black ', 19),
(8 , 'The Large Turf ', 19),
(23, 'On the Beach ', 19),
(2 , 'Portrait of Mona Lisa ', 19),
(27, 'On the Terrace ', 20),
(10, 'The She-Wolf ', 20);
declare @BinCount int = 10;
declare @BinSize int;
select @BinSize = 1 + count(*) / @BinCount from @T;
select T.id,
T.title,
T.price,
1 + rank() over(order by T.price) / @BinSize as decile
from @T as T;
結果:
id title price decile
--- ------------------------------------------- ------ --------------------
19 Deux fillettes, fond jaune et rouge 11 1
17 Flowers in a Pitcher 12 1
5 Composition with Red, Yellow and Blue 12 1
18 La lecon de musique (The Music Lesson) 12 1
9 The Adoration of the Magi 12 1
29 Self-Portrait 14 3
25 Symphony in White, No. 1: The White Girl 14 3
30 The Anatomy Lecture of Dr. Nicolaes Tulp 14 3
20 Les repasseuses (Women Ironing) 14 3
1 The Birth of Venus 15 4
12 Femme se promenant dans une foret exotique 15 4
24 Portrait of the Painter’s Mother 15 4
28 Jeunes filles au piano 15 4
7 Portrait de l artiste (Self-portrait) 16 5
3 The Last Supper 16 5
13 Combat of a Tiger and a Buffalo 16 5
4 The Creation of Man 17 6
22 Le Chemin de Fer 17 6
6 Femmes de Tahiti [Sur la plage] 18 7
21 Le Bar aux Folies-Berg 18 7
26 Lady at the Piano 18 7
15 Remembrance of a Garden 18 7
16 1914 18 7
14 Ancient Sound, Abstract on Black 19 9
8 The Large Turf 19 9
23 On the Beach 19 9
2 Portrait of Mona Lisa 19 9
27 On the Terrace 20 10
10 The She-Wolf 20 10
そして、私はどの十進法に悩まされていません
サンプルデータを含むビン2と8が空になったことに注意してください。
WIDTH_BUCKET関数をシミュレートできます。
CREATE FUNCTION dbo.width_bucket(@val decimal, @min_val decimal, @max_val decimal, @groups int)
RETURNS int
AS
BEGIN
DECLARE @res int;
IF @val = @max_val RETURN @groups;
RETURN CAST((@val - @min_val) / ((@max_val - @min_val) / @groups) AS int) + 1;
END
SELECT
id, title, price, dbo.width_bucket(price, 11.0, 20.0, 10)
FROM
t;
または関数なし:
DECLARE @groups int = 10;
WITH mm AS
(
SELECT MIN(price) AS min_price, MAX(price) AS max_price
FROM t
)
SELECT
id, title, price,
CASE
WHEN
price = max_price THEN @groups
ELSE
CAST((price - min_price) / ((max_price - min_price) / @groups) AS int) + 1
END as ngroup
FROM
t
CROSS APPLY (SELECT min_price, max_price FROM mm) mm;
注価格タイプをintからdecimalに変更しました
id |タイトル|価格| ngroup -:| :----------------------------------------- :---- | -----: 19 | Deuxフィレット、好きなジョーンとルージュ| 11.00 | 1 17 |ピッチャーの花| 12.00 | 2 5 |赤、黄、青の合成| 12.00 | 2 18 | La lecon de musique(音楽レッスン)| 12.00 | 2 9 |賢者の礼拝| 12.00 | 2 29 |自画像| 14.00 | 4 25 |白の交響曲第1番:白い少女| 14.00 | 4 30 |ニコラエス・タルプ博士の解剖学講義| 14.00 | 4 20 | Les repasseuses(女性アイロン)| 14.00 | 4 1 |金星の誕生| 15.00 5 12 | Femme se promenant dans une foret exotique | 15.00 5 24 |画家の母の肖像| 15.00 5 28 |ジューンはauピアノを埋めます| 15.00 5 7 | Portrait de l artiste(自画像)| 16.00 | 6 3 |最後の晩餐| 16.00 | 6 13 |タイガーとバッファローの戦闘| 16.00 | 6 4 |人間の創造| 17.00 | 7 22 |ルシュマンドフェル| 17.00 | 7 6 |フェムスデタヒチ[シュールラプラージュ] | 18.00 | 8 21 | Le Bar aux Folies-Berg | 18.00 | 8 26 |ピアノの女性| 18.00 | 8 15 |庭の記憶| 18.00 | 8 16 | 1914年18.00 | 8 14 |エンシェントサウンド、アブストラクトブラック| 19.00 | 9 8 |大きな芝| 19.00 | 9 23 |ビーチで| 19.00 | 9 2 |モナリザの肖像|写真モナリザの肖像19.00 | 9 27 |テラスで| 20.00 | 10 10 |シーウルフ| 20.00 | 10
db <> fiddle ---(ここ
私は答えを受け入れましたが、私がどのように答えを実践したかを説明したいと思います。
_WITH data AS (SELECT count(*)/10.0 AS bin FROM prints WHERE price<20)
SELECT
id,title,price,
row_number() OVER(ORDER BY price) AS row_number,
ntile(10) OVER(ORDER BY price) AS decile,
floor((row_number() OVER(ORDER BY price)-1)/bin)+1 AS row_decile,
floor((rank() OVER(ORDER BY price)-1)/bin)+1 AS rank_decile,
floor((count(*) OVER(ORDER BY price)-1)/bin)+1 AS count_decile,
bin
FROM prints,data
WHERE price<20
ORDER BY price;
_
興味がある点:
WHERE
句は、扱いにくいビンサイズを強制するためのものです。 _10.0
_は、切り捨てられた整数ではなく、10進数を生成します。row_number()/bin+1
計算は、ネイティブのntile
関数を複製するために含まれています。もちろん、行数が比較的少ない場合は十分位数が欠落するリスクがありますが、少なくとも同じ値を保持します。
今では、どちらのオプションが自分の好みに合っているかを決めることが重要です。