SQLウィンドウ関数とPandasの実装

転載元: SQL ウィンドウ関数と Pandas の実装
原著者: Data Science Growth Notes


冒頭に書かれた
ウィンドウ関数は、複雑な要件に対応する際に、より簡単なデータ処理方法を提供するもので、実際のビジネスでも広く使われており、面接官が注目したい知識の一つでもあります。

ウィンドウ関数とは何ですか?

ウィンドウ関数は、OLAP(Online Analytical Processing)やアナリティック関数(Analytic Function)とも呼ばれ、条件を満たす集合を計算し、データ行ごとに分析結果を返します。以下のとおりであります:

<ウィンドウ関数> OVER (<グループ化の列名> によるパーティション化、<ソートの列名> フレーム句による順序)

1. よく使われるウィンドウ関数

1) 聚合函数:sum()、count()、max()、min()、avg()   
2) 排序函数:row_number()、rank()、dense_rank()    
3) 分布函数:percent_rank()、cume_dist()
4) 平移函数:lead()、lag()
5) 首尾函数:first_val()、last_val()

2、パーティション(パーティション分割)

over中partition by类似group by对数据进行分区,此时,窗口函数会对每个分区单独进行分析,如果不指定partition by将会对整体数据进行分析。

3. 注文方法

over中的order by对分区內的数据进行排序,默认为升序,当order by某个字段中有重复值时会对重复值进行求和,然后对所有数据进行累加。

4. ウィンドウサイズ (frame_clause)

over中的frame_clause指对分区集合指定一个移动窗口,当指定了窗口大小后函数就不会在分区上进行计算,而是基于窗口大小內的数据进行计算。窗口大小的格式如下:
行frame_start
、または
frame_startとframe_endの間の行

このうち、rows はオフセット行数を表します。Frame_start はウィンドウの開始位置を示します。オプションは 3 つあります。

  • デフォルト値である UNBOUNDED PRECEDING は、最初の行から開始することを意味します。
  • N PRECEDING は、前の行から開始することを意味し、前の行のデータが欠落している場合は 0 になります。
  • CURRENT ROW は、現在の行から開始することを意味します。

Frame_end はウィンドウの終了位置を示します。オプションは 3 つあります。

  • CURRENT ROW はデフォルト値で、現在の行からの終わりを示します。
  • N FOLLOWING、現在の行の後の N 行目の終わりを示します。
  • UNBOUNDED FOLLOWING。ウィンドウがパーティションの最後の行で終了することを示します。

SQL のデフォルトのオプションは、UNBOUNDED PRECEDING AND CURRENT ROW の間の行で、統計が最初の行から現在のレコード行までであることを示します。
rows between 1 PRECEDING AND 1 FOLLOWING は、現在の行、前の行、および次の行の集計を示し、主に過去 N か月間のデータ統計に使用されます。
現在の行と UNBOUNDED FOLLOWING の間の行は、現在の行と後続のすべての行を意味します。

ウィンドウ関数を使用する理由

実際のビジネスでは、部門ごとの従業員の給与を計算した後に会社全体の給与の列を追加したり、部門ごとの給与水準を並べ替えて割合を計算したりするなど、データ結果に対して追加の統計を実行する必要が生じることがよくあります。このとき、ウィンドウ関数を使用しない場合、テーブルの関連付けを複数回行う必要がある場合があるため、ウィンドウ関数を使用するとコードが大幅に簡略化され、コードの読み取りおよび書き込みパフォーマンスが向上します。

ウィンドウ関数の使い方

まず、ウィンドウ関数の定義によると、ウィンドウ関数は主に、集計、​​並べ替え、分散、変換、先頭と末尾などのタイプに分類され、各タイプの具体的な適用シナリオは次のとおりです。

集計関数

集計関数はウィンドウ関数としても機能するため、ウィンドウの下でデータ セットの統計を集計する必要がよくありますが、これも広く使用されているウィンドウ関数のカテゴリです。たとえば、A社の各部門の各従業員の売上を数え、各部門の最大値、最小値、平均値、個数をカウントする必要があります。

SQLの実装

select dept, name, salary,
       sum(salary) over(partition by dept) as sum_salary, --各部门员工薪资求和
       avg(salary) over(partition by dept) as avg_salary, --各部门员工薪资求平均
       min(salary) over(partition by dept) as min_salary, --各部门员工薪资求最小
       max(salary) over(partition by dept) as max_salary  --各部门员工薪资求最大值
from data

Pythonの実装

import numpy as np
import pandas as pd
company=["A","B","C"]
data=pd.DataFrame({
    "dept":[company[x] for x in np.random.randint(0,len(company),8)],
    "name":["a","b","c","d","e","f","g","h"],
    "salary":np.random.randint(10,30,8)
}
)
data['sum_salary'] = data.groupby('dept')['salary'].transform('sum')
data['min_salary'] = data.groupby('dept')['salary'].transform('min')
data['mean_salary'] = data.groupby('dept')['salary'].transform('mean')
data['max_salary'] = data.groupby('dept')['salary'].transform('max')
data

ソート機能

並べ替え関数は、グループ化セットやデータ全体をランク付けするためによく使用されます。たとえば、さまざまな部門の従業員の給与を並べ替える必要があります。並べ替え関数は、並べ替え方法に従って次のように分類できます。

1) row_number:对分组內的数据进行"同分不同级"方式排序,不存在序号并列的现象,即使同分时排序也会不同。    
2) rank:对分组內的数据进行"同分同级且不紧密"方式排序,当同分时序号相同,其它排序按正常排名进行排序,即1,2,2,4,5。    
3) dense_rank:对分组內的数据进行"同分同级且紧密"方式排序,当同分时序号相同,其它排序按下一排名进行排序,即1,2,2,3,4。

SQLの実装

select dept, name, salary,
       row_number(salary) over(partition by dept order by salary desc) as row_number, --对各部门员工薪资按同分不同级方式排序
       rank(salary) over(partition by dept order by salary desc) as rank, --对各部门员工薪资按同分同级且紧密方式方式排序
       dense_rank(salary) over(partition by dept order by salary desc) as dense_rank --对各部门员工薪资按同分同级且不紧密方式方式排序
from data

Pythonの実装

import numpy as np
import pandas as pd
company=["A","B","C"]
data=pd.DataFrame({
    "dept":[company[x] for x in np.random.randint(0,len(company),8)],
    "name":["a","b","c","d","e","f","g","h"],
    "salary":np.random.randint(10,15,8)
}
)
data['row_number'] = data.groupby('dept')['salary'].rank(ascending=False,method='first') #同分不同级
data['rank'] = data.groupby('dept')['salary'].rank(ascending=False,method='min')   #"同分同级且不紧密"
data['dense_rank'] = data.groupby('dept')['salary'].rank(ascending=False,method='dense') #"同分同级且紧密"
data

分布関数

分布関数は主に、percent_rank() とcume_dist() の 2 つのカテゴリに分類されます。
percent_rank() : ランキングに従ってパーセンテージを計算することを指します。つまり、ランキングは区間 [0,1] 内にあり、区間の最初の位は 0、最後の位は 1 です。その具体的な式は次のとおりです。

パーセント_ランク()=(ランク−1)/(行−1)パーセント\_ランク() = (ランク - 1) / (行 - 1) \\

cume_dist() : 間隔内の関数の合計に対する、間隔内の現在のランキング以上の行数の比率を指します。主に現在の給与よりも給与やスコアが高いユーザーの割合を判断するために使用されます。

SQLの実装

select dept, name, salary,
       percent_rank(salary) over(partition by dept order by salary desc) as percent_rank,
       cume_dist(salary) over(partition by dept order by salary desc) as cume_dist
from data
import numpy as np
import pandas as pd
company=["A","B","C"]
data=pd.DataFrame({
    "dept":[company[x] for x in np.random.randint(0,len(company),8)],
    "name":["a","b","c","d","e","f","g","h"],
    "salary":np.random.randint(10,15,8)
}
)
# data.groupby('dept')['salary'].rank(ascending=False,method='first',pct=True)
data['percent_rank'] = (data.groupby('dept')['salary'].rank(ascending=False,method='min')-1) / \
                            (data.groupby('dept')['salary'].transform('count')-1)  #如果分组只有一个记录则数据为na 
data['cume_dist'] = data.groupby('dept')['salary'].rank(ascending=False,method='first',pct=True)  #可以结合排序函数的方法使用
data

翻訳機能

分布関数は主に、リード (列名、n) とラグ (列名、n) の 2 つのカテゴリに分類されます。
lead(列名, n) : パーティション内で下にシフトされた n 行のデータを取得します。
lag(列名, n) : パーティション内で上にシフトされた n 行のデータを取得します。

SQLの実装

select dept, name, salary,
lead(salary,1) over(partition by dept order by salary desc ) as lead,
lag(salary,1) over(partition by dept order by salary desc) as lag
from data
import numpy as np
import pandas as pd
company=["A","B","C"]
data=pd.DataFrame({
    "dept":[company[x] for x in np.random.randint(0,len(company),8)],
    "name":["a","b","c","d","e","f","g","h"],
    "salary":np.random.randint(10,30,8)
}
)
data['lead'] = data.sort_values(['dept','salary'],ascending=False).groupby('dept')['salary'].shift(-1) # 分区內向下平移一个单位
data['lag'] = data.sort_values(['dept','salary'],ascending=False).groupby('dept')['salary'].shift(1)  # 分区內向上平移一个单位
data

最初で最後の関数

分布関数は主に、first_val() と last_val() の 2 つのカテゴリに分類されます。
first_val() : パーティション内のデータの最初の行を取得します。
last_val() : パーティション内のデータの最後の行を取得します。

SQLの実装

select dept, name, salary,
first_val(salary) over(partition by dept order by salary desc ) as first_val,
# 由于窗口函数默认的是第一行至当前行,所以在使用last_val()函数时,会出现分区内最后一行和当前行大小一致的情况,因此我们需要将分区偏移量改为第一行至最后一行。
last_val(salary) over(partition by dept order by salary desc rows between UNBOUNDED PRECEDING and UNBOUNDED FOLLOWING) as last_val
from data

Pythonの実装

import numpy as np
import pandas as pd
company=[“A”,“B”,“C”]
data=pd.DataFrame({
“dept”:[company[x] for x in np.random.randint(0,len(company),8)],
“name”:[“a”,“b”,“c”,“d”,“e”,“f”,“g”,“h”],
“salary”:np.random.randint(10,30,8)
}
)
data[‘first_val’] = data.groupby(‘dept’)[‘salary’].transform(‘min’)
data[‘last_val’] = data.groupby(‘dept’)[‘salary’].transform(‘max’)
data

Q&A

Q1: 集計関数とウィンドウ関数の違い

違い: 集計関数は複数のデータを 1 行のデータに集計しますが、ウィンドウ関数はデータの各行の結果を返します。
接続: 一連のデータを分析することがすべてであり、ウィンドウ関数は関数として集計関数を使用できます。
データ結果に対して追加の統計を実行する必要がある場合、多くの場合、ウィンドウ関数を使用する必要があります。

Q2: SQLの実行順序

SQLの記述順序はSELECT、FROM、JOIN、ON、WHERE、GROUP BY、HAVING、ORDER BY、LIMITであり、実行順序は下図のとおりです。

ここで、SQL の実行順序を強調する必要があります。ほとんどの場合、SQL の実行順序についてあまり考える必要はありませんが、ウィンドウ関数の実行順序はほとんどのフィールドの後、フィールド ORDER の前にのみ配置されるためです。 BY、それはかなりです。これは、すべてのフィールドによって生成された一時テーブルの実行に基づいて実行されるウィンドウ関数の操作に基づいています。たとえば、次のとおりです。

上の図から、2 番目の画像に GROUP BY がなく、3 番目の画像に GROUP BY がある場合、GROUP に基づいてウィンドウ関数が実行されるため、最終的なデータの行数が 7 レコードから 3 レコードに変化することがわかります。 BY フィールド 計算は一時テーブルに基づいているため、SQL の実行順序がわかれば、最終結果を簡単に理解できます。

おすすめ

転載: blog.csdn.net/qq_42374697/article/details/127091388