Pyspark:展示数据框列的直方图

46

在pandas数据帧中,我使用以下代码绘制一列的直方图:

my_df.hist(column = 'field_1')

在pyspark数据框中是否有可以实现相同目标的东西?(我在Jupyter Notebook中)谢谢!

8个回答

54

很遗憾,我认为在PySpark Dataframes API中没有干净的plot()hist()函数,但我希望事情最终会朝着这个方向发展。

目前,您可以在Spark中计算直方图,并将计算出的直方图作为条形图绘制。例如:

import pandas as pd
import pyspark.sql as sparksql

# Let's use UCLA's college admission dataset
file_name = "https://stats.idre.ucla.edu/stat/data/binary.csv"

# Creating a pandas dataframe from Sample Data
df_pd = pd.read_csv(file_name)

sql_context = sparksql.SQLcontext(sc)

# Creating a Spark DataFrame from a pandas dataframe
df_spark = sql_context.createDataFrame(df_pd)

df_spark.show(5)

这就是数据的样子:

Out[]:    +-----+---+----+----+
          |admit|gre| gpa|rank|
          +-----+---+----+----+
          |    0|380|3.61|   3|
          |    1|660|3.67|   3|
          |    1|800| 4.0|   1|
          |    1|640|3.19|   4|
          |    0|520|2.93|   4|
          +-----+---+----+----+
          only showing top 5 rows


# This is what we want
df_pandas.hist('gre');

使用df_pandas.hist()绘制的直方图

# Doing the heavy lifting in Spark. We could leverage the `histogram` function from the RDD api

gre_histogram = df_spark.select('gre').rdd.flatMap(lambda x: x).histogram(11)

# Loading the Computed Histogram into a Pandas Dataframe for plotting
pd.DataFrame(
    list(zip(*gre_histogram)), 
    columns=['bin', 'frequency']
).set_index(
    'bin'
).plot(kind='bar');

使用RDD.histogram()计算的直方图


当我从zip迭代器生成数据帧时,出现了错误。鉴于pyspark直方图,使用pd.DataFrame(list(zip(*gre_histogram)), columns=['bin', 'frequency'])创建pandas数据帧更加简洁,并且对我有效。 - Sohan Jain
2
gre_histogram = spark_df.select('gre').rdd.flatMap(lambda x: x).histogram(11) 这一行是胜利之举,将其与下面的 matplotlib 答案结合起来。 - Dan Ciborowski - MSFT
1
我通常使用 DataFrame,没有使用 RDD 的经验。为什么在这里需要应用 flatMap() - Konstantin
6
想知道“_11_”是什么意思的人,它表示的是垃圾箱(bin)的数量。请注意,这里不是指其他含义。 - Suraj Regmi

26
现在,您可以使用 pyspark_dist_explore 包来利用 matplotlib hist 函数处理 Spark DataFrame 数据:
from pyspark_dist_explore import hist
import matplotlib.pyplot as plt

fig, ax = plt.subplots()
hist(ax, my_df.select('field_1'), bins = 20, color=['red'])

本库使用rdd直方图函数来计算bin值。


2
import matplotlib.pyplot as plt - Micah Pearce
3
数据框(data_frame)是一种在统计分析和数据科学中经常使用的数据结构,它类似于电子表格或数据库中的表格。数据框通常由行和列组成,每个列可以包含不同类型的数据,如数字、字符或布尔值。 - Jas
3
如果使用Databricks笔记本,请在末尾添加display(fig) - Cherry Wu

6
另一种解决方案,无需额外导入库,同样高效;首先,使用窗口分割:
import pyspark.sql.functions as F
import pyspark.sql as SQL
win = SQL.Window.partitionBy('column_of_values')

然后你只需要使用窗口分区的count聚合即可: df.select(F.count('column_of_values').over(win).alias('histogram')) 聚合操作在集群的每个分区上执行,不需要向主机进行额外的往返。

我的结果显示为“DataFrame [histogram:bigint]”,你知道为什么它没有生成实际的图表吗?谢谢。 - Elsa Li
我觉得这似乎是情节的架构(没问题),它包含实际数据吗? - Elior Malul
是的,它包含了实际数据。我尝试了不同的方法,但是无法生成图形 :-( - Elsa Li
1
这段代码中没有作图... 该代码的返回值只是一个名为“histogram”的PySpark DataFrame,其中只有一列。 - Thomas
1
这不是很清楚。partitionBy需要一个分组依据或其他东西的分区,你不能使用它来动态生成直方图箱。 - Mehdi LAMRANI

2

histogram方法用于RDD,返回区间范围和区间计数。以下是一个函数,它将这个直方图数据作为直方图绘制。

import numpy as np
import matplotlib.pyplot as mplt
import matplotlib.ticker as mtick

def plotHistogramData(data):
    binSides, binCounts = data

    N = len(binCounts)
    ind = np.arange(N)
    width = 1

    fig, ax = mplt.subplots()
    rects1 = ax.bar(ind+0.5, binCounts, width, color='b')

    ax.set_ylabel('Frequencies')
    ax.set_title('Histogram')
    ax.set_xticks(np.arange(N+1))
    ax.set_xticklabels(binSides)
    ax.xaxis.set_major_formatter(mtick.FormatStrFormatter('%.2e'))
    ax.yaxis.set_major_formatter(mtick.FormatStrFormatter('%.2e'))

    mplt.show()

(此代码假定箱子长度相等。)

binSides, binCounts = data 数据的输入格式是什么? - Elsa Li
1
使用输入 aggData.select(columnName).rdd.flatMap(lambda x: x).histogram(10) 进行工作。问题是:如何在x轴上绘制每个bin内的平均值,而不是bin值(1,2,3,...)? - dierre

1
这段代码简单地创建了一个新的列,将数据分成相等大小的区间,然后按照该列对数据进行分组。 可以将其绘制为条形图以查看直方图。
bins = 10
df.withColumn("factor", F.expr("round(field_1/bins)*bins")).groupBy("factor").count()

3
虽然这段代码可能回答了问题,但是提供关于为什么和/或如何回答问题的额外背景信息可以增加其长期价值。 - dan1st
分析异常:无法解析“bins”,因为给定的输入列是:[field_1];第1行第19个位置。 - nigelhenry

1
通过这种方法,不仅可以在pyspark中获得分布结果,还可以轻松地控制组、nbins或自定义的bin间隔(binn)。(无需导入任何库,包括pandas)
def pyspark_histogram(df, col, group=None, nbins=100, binn=None):
    if not group:
        group = []
    w = Window.partitionBy(group)
    
    df = (
        df
        .withColumn("hist_div", F.lit(binn) if binn else (F.max(col).over(w)-F.min(col).over(w))/nbins)
        .withColumn(col, F.floor(F.col(col)/F.col("hist_div"))*F.col("hist_div"))
        .groupBy(group + [col])
        .agg(F.count("*").alias("count"))
        .withColumn("sum", F.sum("count").over(w))
        .withColumn("percent(%)", F.round(F.col("count")*100.0/F.col("sum"), 1))
        .drop("sum")
        .orderBy(group + [col])
    )
    return df

0

这很简单,而且运行良好。

df.groupby(
  '<group-index>'
).count().select(
  'count'
).rdd.flatMap(
  lambda x: x
).histogram(20)

1
不错。你会如何绘制它? - Justin Lange
如果你在shell中,你需要导出数据并在其他地方进行操作;如果你在Jupyter/Zeppelin/Sagemaker笔记本这种交互式环境中,你可以直接渲染。 - conner.xyz

0
这是我的方法:
import pyspark.sql.functions as f

def plotHist(df, variable, minValue, maxValue, bins = 10):
  factor = bins / (maxValue - minValue + 1)
  (
    df.withColumn('cappedValue', f.least(f.lit(maxValue), f.greatest(f.lit(minValue), variable)))
    .withColumn('buckets', f.round(((f.col('cappedValue')) - minValue)*factor)/factor + minValue)
    .groupBy('buckets').count().display()
  )

有没有人知道一种更优雅的方法来同时限制一个变量的上下界?

根据目前的写法,你的回答不够清晰。请编辑以添加更多细节,帮助其他人理解这如何回答所提出的问题。你可以在帮助中心找到关于如何撰写好回答的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接