如何在sql和pandas中获得相同的百分比排名?

tpgth1q7  于 2021-07-24  发布在  Java
关注(0)|答案(1)|浏览(532)

我在学习 pyspark 它使用 HiveQL 有趣的是百分比排名给出了两种不同的答案 pyspark-sql 以及 pandas .
sql代码的问题源:https://www.windowfunctions.com/questions/ranking/3
如何在pandas中获得与sql相同的结果?

两个问题

给出与sql相同结果的python代码是什么?
什么样的sql代码能给出与pandas相同的结果?

Pypark sql

  1. q = """
  2. select name, weight,
  3. percent_rank() over (order by weight) as percent_rank_wt
  4. from cats
  5. order by weight
  6. """
  7. spark.sql(q).show()
  8. SQL gives this table. I would like same table using pandas.
  9. +-------+------+-------------------+
  10. | name|weight| percent_rank_wt|
  11. +-------+------+-------------------+
  12. | Tigger| 3.8| 0.0|
  13. | Molly| 4.2|0.09090909090909091|
  14. | Ashes| 4.5|0.18181818181818182|
  15. |Charlie| 4.8| 0.2727272727272727|
  16. | Smudge| 4.9|0.36363636363636365|
  17. | Felix| 5.0|0.45454545454545453|
  18. | Puss| 5.1| 0.5454545454545454|
  19. | Millie| 5.4| 0.6363636363636364|
  20. | Alfie| 5.5| 0.7272727272727273|
  21. | Misty| 5.7| 0.8181818181818182|
  22. | Oscar| 6.1| 0.9090909090909091|
  23. | Smokey| 6.1| 0.9090909090909091|
  24. +-------+------+-------------------+

Pandas

  1. methods = {'average', 'min', 'max', 'first', 'dense'}
  2. df[['name','weight']].sort_values('weight').assign(
  3. pct_avg=df['weight'].rank(pct=True,method='average'),
  4. pct_min=df['weight'].rank(pct=True,method='min'),
  5. pct_max=df['weight'].rank(pct=True,method='max'),
  6. pct_first=df['weight'].rank(pct=True,method='first'),
  7. pct_dense=df['weight'].rank(pct=True,method='dense')
  8. ).sort_values('weight')
  9. name weight pct_avg pct_min pct_max pct_first pct_dense
  10. 4 Tigger 3.8 0.083333 0.083333 0.083333 0.083333 0.090909
  11. 0 Molly 4.2 0.166667 0.166667 0.166667 0.166667 0.181818
  12. 1 Ashes 4.5 0.250000 0.250000 0.250000 0.250000 0.272727
  13. 11 Charlie 4.8 0.333333 0.333333 0.333333 0.333333 0.363636
  14. 3 Smudge 4.9 0.416667 0.416667 0.416667 0.416667 0.454545
  15. 2 Felix 5.0 0.500000 0.500000 0.500000 0.500000 0.545455
  16. 9 Puss 5.1 0.583333 0.583333 0.583333 0.583333 0.636364
  17. 7 Millie 5.4 0.666667 0.666667 0.666667 0.666667 0.727273
  18. 5 Alfie 5.5 0.750000 0.750000 0.750000 0.750000 0.818182
  19. 8 Misty 5.7 0.833333 0.833333 0.833333 0.833333 0.909091
  20. 6 Oscar 6.1 0.958333 0.916667 1.000000 0.916667 1.000000
  21. 10 Smokey 6.1 0.958333 0.916667 1.000000 1.000000 1.000000

设置

  1. import numpy as np
  2. import pandas as pd
  3. import pyspark
  4. from pyspark.sql.types import *
  5. from pyspark.sql import functions as F
  6. from pyspark.sql.window import Window
  7. from pyspark import SparkConf, SparkContext, SQLContext
  8. spark = pyspark.sql.SparkSession.builder.appName('app').getOrCreate()
  9. sc = spark.sparkContext
  10. sqlContext = SQLContext(sc)
  11. df = pd.DataFrame({
  12. 'name': [
  13. 'Molly', 'Ashes', 'Felix', 'Smudge', 'Tigger', 'Alfie', 'Oscar',
  14. 'Millie', 'Misty', 'Puss', 'Smokey', 'Charlie'
  15. ],
  16. 'breed': [
  17. 'Persian', 'Persian', 'Persian', 'British Shorthair',
  18. 'British Shorthair', 'Siamese', 'Siamese', 'Maine Coon', 'Maine Coon',
  19. 'Maine Coon', 'Maine Coon', 'British Shorthair'
  20. ],
  21. 'weight': [4.2, 4.5, 5.0, 4.9, 3.8, 5.5, 6.1, 5.4, 5.7, 5.1, 6.1, 4.8],
  22. 'color': [
  23. 'Black', 'Black', 'Tortoiseshell', 'Black', 'Tortoiseshell', 'Brown',
  24. 'Black', 'Tortoiseshell', 'Brown', 'Tortoiseshell', 'Brown', 'Black'
  25. ],
  26. 'age': [1, 5, 2, 4, 2, 5, 1, 5, 2, 2, 4, 4]
  27. })
  28. schema = StructType([
  29. StructField('name', StringType(), True),
  30. StructField('breed', StringType(), True),
  31. StructField('weight', DoubleType(), True),
  32. StructField('color', StringType(), True),
  33. StructField('age', IntegerType(), True),
  34. ])
  35. sdf = sqlContext.createDataFrame(df, schema)
  36. sdf.createOrReplaceTempView("cats")
t0ybt7op

t0ybt7op1#

sql的 percent_rank 和Pandas的不完全一样 rank . 主要有两个区别:
sql的 percent_rank 从计算中排除当前行。因此,如果表有11行,则每行仅使用其他10行计算结果。Pandas rank 包括所有行。
sql的 percent_rank 给出严格小于当前行的行数。Pandas rank 不支持这样做的方法。

给出与sql相同结果的python代码是什么?

获取sql的等价项 percent_rank 在pandas中,您实际上可以对 rank 结果:

  1. (df['weight'].rank(method='min')-1) / (len(df['weight'])-1)

这个 -1 在分子中得到的是严格小于当前行的行数,而 -1 在分母中得到的是计算不包括当前行的结果。

什么样的sql代码能给出与pandas相同的结果?

这取决于你在Pandas身上使用的方法 rank ,但您可能需要sql cume_dist .

展开查看全部

相关问题