it-swarm-eu.dev

Berechnung der Perzentilrangierungen in MS SQL

Was ist der beste Weg, um Perzentil-Rankings (z. B. das 90. Perzentil oder den Medianwert) in MSSQL 2005 zu berechnen?

Ich möchte in der Lage sein, das 25., das Median und das 75. Perzentil für eine einzelne Spalte von Scores auszuwählen (vorzugsweise in einem einzigen Datensatz, damit ich es mit Durchschnitt, Max und Min kombinieren kann). Die Tabellenausgabe der Ergebnisse könnte beispielsweise folgendermaßen lauten:

Group  MinScore  MaxScore  AvgScore  pct25  median  pct75
-----  --------  --------  --------  -----  ------  -----
T1     52        96        74        68     76      84
T2     48        98        74        68     75      85
25
Soldarnal

Ich würde denken, dass dies die einfachste Lösung wäre:

SELECT TOP N PERCENT FROM TheTable ORDER BY TheScore DESC

Wobei N = (100 - gewünschtes Perzentil). Wenn Sie also alle Zeilen im 90. Perzentil haben möchten, würden Sie die oberen 10% auswählen.

Ich bin mir nicht sicher, was Sie mit "vorzugsweise in einem einzigen Datensatz" meinen. Meinen Sie damit, in welches Perzentil eines bestimmten Datensatzes ein bestimmter Wert fallen würde? z.B. Möchten Sie Aussagen wie "Ihre Punktzahl ist 83, was Sie in das 91. Perzentil bringt" machen können. ?

EDIT: OK, ich dachte noch etwas über Ihre Frage nach und kam zu dieser Interpretation. Fragen Sie, wie Sie den Cutoff-Wert für ein bestimmtes Perzentil berechnen können? z.B. Etwas wie das: Um im 90. Perzentil zu sein, müssen Sie eine Punktzahl von mehr als 78 haben.

Wenn ja, funktioniert diese Abfrage. Ich mag Unterabfragen jedoch nicht, also würde ich je nachdem, wofür sie gedacht war, wahrscheinlich versuchen, eine elegantere Lösung zu finden. Es wird jedoch ein einzelner Datensatz mit einer einzigen Bewertung zurückgegeben.

-- Find the minimum score for all scores in the 90th percentile
SELECT Min(subq.TheScore) FROM
(SELECT TOP 10 PERCENT TheScore FROM TheTable
ORDER BY TheScore DESC) AS subq
14
Matt

Schauen Sie sich den NTILE-Befehl an - er gibt Ihnen ganz leicht Perzentile!

SELECT  SalesOrderID, 
    OrderQty,
    RowNum = Row_Number() OVER(Order By OrderQty),
    Rnk = RANK() OVER(ORDER BY OrderQty),
    DenseRnk = DENSE_RANK() OVER(ORDER BY OrderQty),
    NTile4  = NTILE(4) OVER(ORDER BY OrderQty)
FROM Sales.SalesOrderDetail 
WHERE SalesOrderID IN (43689, 63181)
9
Elizabeth

Wie wäre es damit:

SELECT
  Group,
  75_percentile =  MAX(case when NTILE(4) OVER(ORDER BY score ASC) = 3 then score  else 0 end),
  90_percentile =  MAX(case when NTILE(10) OVER(ORDER BY score  ASC) = 9 then score  else 0 end)     
FROM TheScore
GROUP BY Group
2
Paul

Das 50. Perzentil entspricht dem Median. Wenn Sie ein anderes Perzentil berechnen, sagen Sie das 80., sortieren Sie die Daten für die 80 Prozent der Daten in aufsteigender Reihenfolge und die anderen 20 Prozent in absteigender Reihenfolge und nehmen Sie den Durchschnitt der beiden mittleren Werte an.

NB: Die mittlere Abfrage gibt es schon lange, aber ich kann mich nicht erinnern, wo genau ich sie herbekommen habe. Ich habe sie nur geändert, um andere Perzentile zu berechnen.

DECLARE @Temp TABLE(Id INT IDENTITY(1,1), DATA DECIMAL(10,5))

INSERT INTO @Temp VALUES(0)
INSERT INTO @Temp VALUES(2)
INSERT INTO @Temp VALUES(8)
INSERT INTO @Temp VALUES(4)
INSERT INTO @Temp VALUES(3)
INSERT INTO @Temp VALUES(6)
INSERT INTO @Temp VALUES(6)
INSERT INTO @Temp VALUES(6) 
INSERT INTO @Temp VALUES(7)
INSERT INTO @Temp VALUES(0)
INSERT INTO @Temp VALUES(1)
INSERT INTO @Temp VALUES(NULL)


--50th percentile or median
SELECT ((
        SELECT TOP 1 DATA
        FROM   (
                SELECT  TOP 50 PERCENT DATA
                FROM    @Temp
                WHERE   DATA IS NOT NULL
                ORDER BY DATA
                ) AS A
        ORDER BY DATA DESC) + 
        (
        SELECT TOP 1 DATA
        FROM   (
                SELECT  TOP 50 PERCENT DATA
                FROM    @Temp
                WHERE   DATA IS NOT NULL
                ORDER BY DATA DESC
                ) AS A
        ORDER BY DATA ASC)) / 2.0


--90th percentile 
SELECT ((
        SELECT TOP 1 DATA
        FROM   (
                SELECT  TOP 90 PERCENT DATA
                FROM    @Temp
                WHERE   DATA IS NOT NULL
                ORDER BY DATA
                ) AS A
        ORDER BY DATA DESC) + 
        (
        SELECT TOP 1 DATA
        FROM   (
                SELECT  TOP 10 PERCENT DATA
                FROM    @Temp
                WHERE   DATA IS NOT NULL
                ORDER BY DATA DESC
                ) AS A
        ORDER BY DATA ASC)) / 2.0


--75th percentile
SELECT ((
        SELECT TOP 1 DATA
        FROM   (
                SELECT  TOP 75 PERCENT DATA
                FROM    @Temp
                WHERE   DATA IS NOT NULL
                ORDER BY DATA
                ) AS A
        ORDER BY DATA DESC) + 
        (
        SELECT TOP 1 DATA
        FROM   (
                SELECT  TOP 25 PERCENT DATA
                FROM    @Temp
                WHERE   DATA IS NOT NULL
                ORDER BY DATA DESC
                ) AS A
        ORDER BY DATA ASC)) / 2.0
1
Kay Aliu

Ich habe etwas mehr daran gearbeitet und hier ist was ich bisher gefunden habe:

CREATE PROCEDURE [dbo].[TestGetPercentile]

@percentile as float,
@resultval as float output

AS

BEGIN

WITH scores(score, prev_rank, curr_rank, next_rank) AS (
    SELECT dblScore,
        (ROW_NUMBER() OVER ( ORDER BY dblScore ) - 1.0) / ((SELECT COUNT(*) FROM TestScores) + 1)  [prev_rank],
        (ROW_NUMBER() OVER ( ORDER BY dblScore ) + 0.0) / ((SELECT COUNT(*) FROM TestScores) + 1)  [curr_rank],
        (ROW_NUMBER() OVER ( ORDER BY dblScore ) + 1.0) / ((SELECT COUNT(*) FROM TestScores) + 1)  [next_rank]
    FROM TestScores
)

SELECT @resultval = (
    SELECT TOP 1 
    CASE WHEN t1.score = t2.score
        THEN t1.score
    ELSE
        t1.score + (t2.score - t1.score) * ((@percentile - t1.curr_rank) / (t2.curr_rank - t1.curr_rank))
    END
    FROM scores t1, scores t2
    WHERE (t1.curr_rank = @percentile OR (t1.curr_rank < @percentile AND t1.next_rank > @percentile))
        AND (t2.curr_rank = @percentile OR (t2.curr_rank > @percentile AND t2.prev_rank < @percentile))
)

END

Dann mache ich in einer anderen gespeicherten Prozedur folgendes:

DECLARE @pct25 float;
DECLARE @pct50 float;
DECLARE @pct75 float;

exec SurveyGetPercentile .25, @pct25 output
exec SurveyGetPercentile .50, @pct50 output
exec SurveyGetPercentile .75, @pct75 output

Select
    min(dblScore) as minScore,
    max(dblScore) as maxScore,
    avg(dblScore) as avgScore,
    @pct25 as percentile25,
    @pct50 as percentile50,
    @pct75 as percentile75
From TestScores

Es tut immer noch nicht ganz das, wonach ich suche. Dies wird die Statistiken für alle Tests erhalten. Ich möchte jedoch in der Lage sein, aus einer TestScores-Tabelle auszuwählen, die mehrere verschiedene Tests enthält, und für jeden Test die gleichen Werte zu erhalten (wie ich es in meiner Beispieltabelle in meiner Frage habe).

1
Soldarnal

Perzentil wird berechnet durch

(Rank -1) /(total_rows -1) wenn Sie die Werte in aufsteigender Reihenfolge sortieren.

Die folgende Abfrage gibt Ihnen einen Perzentilwert zwischen 0 und 1. Die Person mit den niedrigsten Noten hat ein Perzentil von 0.

SELECT Name, marks, (rank_1-1)/((select count(*) as total_1 from table)-1)as percentile_rank
from
(
SELECT Name,
       Marks,
       RANK() OVER (ORDER BY Marks) AS rank_1
       from table
) as A
0
Debasmita

ich würde wahrscheinlich einen SQL Server 2005 verwenden 

zeilennummer () vorbei (nach Punktzahl)/(Anzahl (*) aus Punktzahlen auswählen)

oder etwas in diese Richtung. 

0
karl prosser

ich würde etwas tun wie:

select @n = count(*) from tbl1
select @median = @n / 2
select @p75 = @n * 3 / 4
select @p90 = @n * 9 / 10

select top 1 score from (select top @median score from tbl1 order by score asc) order by score desc

ist das richtig?

0
syap