【问题标题】:Line Plot of Specific Columns from Pyspark DataframePyspark Dataframe 中特定列的线图
【发布时间】:2023-01-13 10:43:19
【问题描述】:

我有以下数据,需要创建 x = Date 和 y = count 的折线图。

我用来创建下面数据框的代码来自另一个数据框。

df7=df7.select("*",
concat(col("Month"),lit("/"),col("Year")).alias("Date"))
df7.show()

我已将 matplotlib.pyplot 作为 plt 导入,但仍然出现错误。

我在不同变体中使用的绘图代码如下:

df.plot(x = 'Date', y = 'Count')

df.plot(kind = 'line')

我不断收到此错误:

AttributeError: 'DataFrame' object has no attribute 'plt'/'plot'

【问题讨论】:

  • 我也尝试了 plot 并得到了同样的错误。 AttributeError: 'DataFrame' 对象没有属性 'plot'
  • 请创建一个minimal reproducible example。包括代码、错误和数据作为文本.
  • 不幸的是,当我从 pandas 复制并粘贴表格时,格式永远不会遵循。
  • 您需要将数据框从 spark 数据框转换为 pandas 数据框。尝试 df_pd= df.toPandas() 然后在 df_pd 上运行绘图。

标签: pandas dataframe pyspark linechart


【解决方案1】:

请注意,使用 df_pd= df.toPandas() 有时会很昂贵,如果您处理大量记录,如 M 规模,您可能会遇到 OOM error数据块介质,否则您的会话可能会由于驱动器的 RAM 内存不足而崩溃。长话短说,通过使用toPandas(),实际上,您不再使用基于 spark 或分布式计算资源!因此,或者,您可以遵循以下方法: 那么让我们从一个简单的例子开始:

import time
import datetime as dt
from pyspark.sql import functions as F
from pyspark.sql.functions import *
from pyspark.sql.functions import dayofmonth, dayofweek
from pyspark.sql.types import StructType,StructField, StringType, IntegerType, TimestampType, DateType

dict2  = [("2021-08-11 04:05:06", 10),
         ("2021-08-12 04:15:06", 17),
         ("2021-08-13 09:15:26", 25),
         ("2021-08-14 11:04:06", 68),
         ("2021-08-15 14:55:16", 50),
         ("2021-08-16 04:12:11", 2),

  ]

schema = StructType([ 

    StructField("timestamp",     StringType(),    True), 
    StructField("count",         IntegerType(),    True), 
  ])
 
#create a Spark dataframe
sqlCtx = SQLContext(sc)
sdf = sqlCtx.createDataFrame(data=dict2,schema=schema)
sdf.printSchema()
sdf.show(truncate=False)

#Generate date and timestamp
new_df = sdf.withColumn('timestamp',    F.to_timestamp("timestamp", "yyyy-MM-dd HH:mm:ss").cast(TimestampType())) 
            .withColumn('date',         F.to_date("timestamp",      "yyyy-MM-dd").cast(DateType())) 
            .select('timestamp', 'date', 'count') 

new_df.show(truncate = False)  

#root
# |-- timestamp: string (nullable = true)
# |-- count: integer (nullable = true)

#+-------------------+-----+
#|timestamp          |count|
#+-------------------+-----+
#|2021-08-11 04:05:06|10   |
#|2021-08-12 04:15:06|17   |
#|2021-08-13 09:15:26|25   |
#|2021-08-14 11:04:06|68   |
#|2021-08-15 14:55:16|50   |
#|2021-08-16 04:12:11|2    |
#+-------------------+-----+

#+-------------------+----------+-----+
#|timestamp          |date      |count|
#+-------------------+----------+-----+
#|2021-08-11 04:05:06|2021-08-11|10   |
#|2021-08-12 04:15:06|2021-08-12|17   |
#|2021-08-13 09:15:26|2021-08-13|25   |
#|2021-08-14 11:04:06|2021-08-14|68   |
#|2021-08-15 14:55:16|2021-08-15|50   |
#|2021-08-16 04:12:11|2021-08-16|2    |
#+-------------------+----------+-----+

现在你需要collect()你想要在没有 Pandas 的情况下反映你的情节的列的值;当然,这在大数据记录中很昂贵并且需要(很长)时间,但它确实有效。现在您可以应用以下方式之一:

#for bighigh # of records
xlabels = new_df.select("timestamp").rdd.flatMap(list).collect()
ylabels = new_df.select("count").rdd.flatMap(list).collect()

#for limited # of records
xlabels   = [val.timestamp  for val in new_df.select('timestamp').collect()]
ylabels   = [val.count      for val in new_df.select('count').collect()]

绘制:

import matplotlib.pyplot as plt
import matplotlib.dates as md

fig, ax = plt.subplots(figsize=(10,6))
plt.plot(xlabels,     ylabels,   color='blue',    label="event's count") #, marker="o"
plt.scatter(xlabels,  ylabels,   color='cyan', marker='d', s=70)

plt.xticks(rotation=45)
plt.ylabel('Event counts 
# of records', fontsize=15)
plt.xlabel('timestamp', fontsize=15)
plt.title('Events over time', fontsize=15, color='darkred', weight='bold')
plt.legend(['# of records'], loc='upper right')

plt.show()

基于 cmets,我假设由于在 x 轴时间戳下打印的大量记录不可读,如下图所示:

要解决此问题,您需要使用以下方法正确排列 x 轴刻度,以便它们不会彼此重叠或最终并排绘制:

import pandas as pd
import matplotlib.pyplot as plt

x=xlabels
y=ylabels

#Note 1: if you use Pandas dataFrame after .toPandas()
#x=df['timestamp']
#y=df['count']

##Note 2: if you use Pandas dataFrame after .toPandas()
# convert the datetime column to a datetime type and assign it back to the column
df.timestamp = pd.to_datetime(df.timestamp)

fig, ax = plt.subplots( figsize=(12,8))

plt.plot(x, y)

ax.legend(['# of records'])
ax.set_xlabel('Timestamp')
ax.set_ylabel('Event counts 
# of records')

# beautify the x-labels
import matplotlib.dates as md

plt.gcf().autofmt_xdate()
myFmt = md.DateFormatter('%Y-%m-%d %H:%M:%S.%f')
plt.gca().xaxis.set_major_formatter(myFmt)

plt.show()
plt.close()

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-06-13
    • 2022-01-06
    • 1970-01-01
    • 2021-12-26
    相关资源
    最近更新 更多