本文主要用于解决实验报告中2/3/4/6四道题目
第五题和第七题是直接按照实验报告来做即可,没有编程要求。
基于jupyter notebook来写,并且实验数据自行准备,学号为双号,单号仅供参考
代码是第一次写的复杂版本(屎山代码.bushi),非本人最终版本,但运行结果一致。
实验报告不要求可视化部分,可忽略。
初版,后续可能精修,看心情。
最近在搭自己的博客,忙着想方设法的睡觉,时间很不充裕。
首先需要在jupyter notebook里下载好spark库
!pip install pyspark --user
注意,Linux虚拟机中是需要开启spark的,启动spark后新建一个终端启动jupyter然后在浏览器特定端口下用jupyter进行数据分析。
实验内容与步骤:
第二题
2 音乐数据的spark+python分析(https://dblab.xmu.edu.cn/blog/2744/,基于Spark的音乐专辑数据分析展示python)
(1)查询滚石网站、MTV、音乐达人三者评分合计最高的前10条专辑信息,按评分降序排列(代码与结果截图);
(2)总销量前6的专辑类型,在不同评分体系中的平均评分(按销量降序排列)。
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, sum as _sum, avg
import matplotlib.pyplot as plt
# 初始化Spark会话
spark = SparkSession.builder.appName("Music Album Analysis").getOrCreate()
# 加载数据
df = spark.read.csv("C:/Users/安全工程4班王鑫/Desktop/虚拟机软件/music-analysis/albums.csv", header=True, inferSchema=True)
# 计算每个专辑的总评分
df_with_scores = df.withColumn("total_critic_score", col("rolling_stone_critic") + col("mtv_critic") + col("music_maniac_critic"))
# 找出总评分最高的前10个专辑
top_albums = df_with_scores.orderBy(col("total_critic_score").desc()).limit(10)
# 显示前10个专辑的表格
top_albums.show()
# 将Spark DataFrame转换为Pandas DataFrame用于可视化
top_albums_pandas = top_albums.toPandas()
# 使用Matplotlib进行可视化
plt.figure(figsize=(10, 6))
plt.barh(top_albums_pandas['album_title'], top_albums_pandas['total_critic_score'])
plt.xlabel('Total Critic Score')
plt.ylabel('Album Title')
plt.title('Top 10 Albums Based on Critic Scores')
plt.gca().invert_yaxis()
plt.show()
# 计算总销量前6的专辑类型
genre_sales = df.groupBy("genre").agg(_sum("num_of_sales").alias("total_sales")).orderBy(col("total_sales").desc()).limit(6)
# 计算这些顶级类型的平均评分
top_genres_scores = df.join(genre_sales, "genre").groupBy("genre").agg(avg("rolling_stone_critic").alias("avg_rolling_stone"), avg("mtv_critic").alias("avg_mtv"), avg("music_maniac_critic").alias("avg_music_maniac"))
# 显示这些顶级类型的评分表格
top_genres_scores.show()
# 将结果转换为Pandas DataFrame用于可视化
top_genres_scores_pandas = top_genres_scores.toPandas()
# 绘制每个评分体系的平均评分
top_genres_scores_pandas.plot(kind='bar', x='genre', y=['avg_rolling_stone', 'avg_mtv', 'avg_music_maniac'], figsize=(10, 6))
plt.ylabel('Average Score')
plt.title('Average Scores by Genre in Top Selling Genres')
plt.show()
# 关闭Spark会话
spark.stop()
再次强调虽然能得出正确结果但是是不符合要求的非精修形式
请自行修改表示形式,以表格的形式展现
可视化版代码结果:
精修版本结果:再次注意:老师不要求进行可视化。
(代码因为是本人自用的怕查重,就不贴上去了,也不要来问我,我不给 X ~L~ X)
第三题
3 淘宝数据的spark+python分析(https://dblab.xmu.edu.cn/blog/3525/,基于Spark的淘宝数据分析scala)
(1)销量前5的日期,降序排列;(双号)
(2)销量前5的小时,降序排列;
(3)购买合计/收藏合计 的比例;(双号)
代码:
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, hour, count, when
import matplotlib.pyplot as plt
spark = SparkSession.builder.appName("Taobao Data Analysis").getOrCreate()
df = spark.read.option("header", "true").csv("C:/Users/安全工程4班王鑫/Desktop/虚拟机软件/Processed_UserBehavior.csv")
# 使用 Spark SQL 函数处理日期和时间
df = df.withColumn("date", col("day"))
df = df.withColumn("hour", hour("time"))
# (1) 销量前5的日期,降序排列
sales_by_date = df.filter(col("action") == "buy").groupBy("date").agg(count("*").alias("total_sales"))
top5_sales_dates = sales_by_date.orderBy(col("total_sales").desc()).limit(5)
# 展示销量前5的日期
top5_sales_dates.show()
# 可视化销量前5的日期 - 折线图
top5_sales_dates_pd = top5_sales_dates.toPandas()
top5_sales_dates_pd.sort_values('date', inplace=True)
plt.figure(figsize=(10, 6))
plt.plot(top5_sales_dates_pd['date'], top5_sales_dates_pd['total_sales'], marker='o')
plt.xlabel('Date')
plt.ylabel('Total Sales')
plt.title('Top 5 Sales Dates')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# (2) 销量前5的小时,降序排列
sales_by_hour = df.filter(col("action") == "buy").groupBy("hour").agg(count("*").alias("total_sales"))
top5_sales_hours = sales_by_hour.orderBy(col("total_sales").desc()).limit(5)
# 展示销量前5的小时
top5_sales_hours.show()
# 可视化销量前5的小时 - 折线图
top5_sales_hours_pd = top5_sales_hours.toPandas()
top5_sales_hours_pd.sort_values('hour', inplace=True)
plt.figure(figsize=(10, 6))
plt.plot(top5_sales_hours_pd['hour'], top5_sales_hours_pd['total_sales'], marker='o')
plt.xlabel('Hour of the Day')
plt.ylabel('Total Sales')
plt.title('Sales by Hour')
plt.xticks(range(0, 24))
plt.grid(True)
plt.tight_layout()
plt.show()
# (3) 购买合计/收藏合计 的比例
purchase_count = df.filter(col("action") == "buy").count()
favorite_count = df.filter(col("action") == "fav").count()
purchase_to_favorite_ratio = [
('Purchase', purchase_count),
('Favorite', favorite_count - purchase_count)
]
# 展示购买与收藏的比例
print(f"Purchase to Favorite Ratio: {purchase_favorite_ratio}")
# 可视化购买与收藏的比例 - 饼图
labels = [x[0] for x in purchase_to_favorite_ratio]
sizes = [x[1] for x in purchase_to_favorite_ratio]
plt.figure(figsize=(8, 8))
plt.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=140)
plt.title('Purchase to Favorite Ratio')
plt.show()
# 关闭Spark会话
spark.stop()
运行结果:
第四题
4 碳排放数据的Spark+Python分析(https://dblab.xmu.edu.cn/blog/4400/,基于CO2排放量数据集的数据分析及可视化python)
(1)2011-2021年平均排放量最高的前5个国家与平均排放量;(双号)
(2)在2016-2021年中,中国Gas、Oil、Coal排放量比例;(双号)
代码:
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, avg
import matplotlib.pyplot as plt
spark = SparkSession.builder.appName("CO2 Emissions Analysis").getOrCreate()
data_path = "C:/Users/安全工程4班王鑫/Desktop/虚拟机软件/GCB2022v27_MtCO2_flat.csv"
df = spark.read.option("header", "true").csv(data_path)
# 数据清洗:过滤出2011-2021年的数据,并转换为合适的数据类型
df_clean = df.filter((col("Year") >= 2011) & (col("Year") <= 2021))
df_clean = df_clean.withColumn("Total", col("Total").cast("float"))
df_clean = df_clean.withColumn("Coal", col("Coal").cast("float"))
df_clean = df_clean.withColumn("Oil", col("Oil").cast("float"))
df_clean = df_clean.withColumn("Gas", col("Gas").cast("float"))
# (1) 2011-2021年平均排放量最高的前5个国家与平均排放量
avg_emissions_by_country = df_clean.groupBy("Country").agg(avg("Total").alias("Avg_Total"))
top5_countries = avg_emissions_by_country.orderBy(col("Avg_Total").desc()).limit(6)
# 展示平均排放量最高的前5个国家
top5_countries.show()
# 可视化平均排放量最高的前5个国家 - 柱状图
top5_countries_pd = top5_countries.toPandas()
plt.figure(figsize=(10, 6))
top5_countries_pd.plot(kind='bar', x='Country', y='Avg_Total', legend=None)
plt.xlabel('Country')
plt.ylabel('Average Total Emissions')
plt.title('Top 5 Countries by Average CO2 Emissions (2011-2021)')
plt.xticks(rotation=45)
plt.tight_layout()
plt.show()
# (2) 在2016-2021年中,中国Gas、Oil、Coal排放量比例
china_df = df_clean.filter((col("Country") == "China") & (col("Year") >= 2016))
china_emissions = china_df.select("Coal", "Oil", "Gas").groupBy().sum().collect()[0]
# 展示中国的Gas、Oil、Coal排放量比例
china_emissions_proportions = {
"Coal": china_emissions["sum(Coal)"],
"Oil": china_emissions["sum(Oil)"],
"Gas": china_emissions["sum(Gas)"]
}
# 可视化中国的Gas、Oil、Coal排放量比例 - 饼图
labels = china_emissions_proportions.keys()
sizes = china_emissions_proportions.values()
plt.figure(figsize=(8, 8))
plt.pie(sizes, labels=labels, autopct='%1.1f%%', startangle=140)
plt.title('China CO2 Emissions Proportions (2016-2021)')
plt.show()
# 关闭Spark会话
spark.stop()
运行结果:
第五题
第五题对应博客一步一步来即可
https://dblab.xmu.edu.cn/blog/3212/
正确运行结果大概如下
第六题
6 豆瓣电影数据的Spark+Python分析(https://dblab.xmu.edu.cn/blog/2951/,基于Flink的对豆瓣电影数据的分析与处理scala)
(1)每年上映电影数量最多的前三名电影类型,显示年份、电影类型、电影数量。按年份升序、数量降序排列;(双号)
(2)每年平均评分前3的制片国家/地区(双号)
代码:
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, explode, split, avg, count
from pyspark.sql.window import Window
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
import numpy as np
import plotly.graph_objects as go
import pandas as pd
spark = SparkSession.builder.appName("Douban Movie Data Analysis").getOrCreate()
movies_df = spark.read.csv("C:/Users/安全工程4班王鑫/Desktop/虚拟机软件/douban_2.csv", header=True, inferSchema=True)
movies_df = movies_df.dropna(subset=["year", "genre", "country", "rating"])
genre_df = movies_df.withColumn("genre", explode(split(col("genre"), "/")))
genre_counts = genre_df.groupBy("year", "genre").count()
window_genre = Window.partitionBy("year").orderBy(col("count").desc())
top_genres_by_year = genre_counts.withColumn("rank", rank().over(window_genre)).filter(col("rank") <= 3)
top_genres_by_year = top_genres_by_year.orderBy("year", col("count").desc())
country_df = movies_df.withColumn("country", explode(split(col("country"), "/")))
country_avg_ratings = country_df.groupBy("year", "country").agg(avg("rating").alias("avg_rating"))
window_country = Window.partitionBy("year").orderBy(col("avg_rating").desc())
top_countries_by_year = country_avg_ratings.withColumn("rank", rank().over(window_country)).filter(col("rank") <= 3)
top_countries_by_year = top_countries_by_year.orderBy("year", col("avg_rating").desc())
# 数据处理和表格创建
top_genres_grouped = top_genres_by_year_pd.groupby(['year', 'rank']).agg({
'genre': 'first',
'count': 'first'
}).reset_index()
top_genres_pivot = top_genres_grouped.pivot(index='year', columns='rank', values=['genre', 'count'])
top_genres_pivot.columns = ['_'.join(map(str, col)).strip() for col in top_genres_pivot.columns.values]
top_genres_pivot.rename(columns={
'genre_1': '数量最多电影类型',
'count_1': '数量最多电影数量',
'genre_2': '数量第二电影类型',
'count_2': '数量第二电影数量',
'genre_3': '数量第三电影类型',
'count_3': '数量第三电影数量'
}, inplace=True)
print(top_genres_pivot)
top_countries_grouped = top_countries_by_year_pd.groupby(['year', 'rank']).agg({
'country': 'first',
'avg_rating': 'first'
}).reset_index()
top_countries_pivot = top_countries_grouped.pivot(index='year', columns='rank', values=['country', 'avg_rating'])
top_countries_pivot.columns = ['_'.join(map(str, col)).strip() for col in top_countries_pivot.columns.values]
top_countries_pivot.rename(columns={
'country_1': '平均评分最高国家',
'avg_rating_1': '平均评分最高值',
'country_2': '平均评分第二国家',
'avg_rating_2': '平均评分第二值',
'country_3': '平均评分第三国家',
'avg_rating_3': '平均评分第三值'
}, inplace=True)
print(top_countries_pivot)
genre_to_index = {genre: index for index, genre in enumerate(top_genres_by_year_pd['genre'].unique())}
y_genre = [genre_to_index[genre] for genre in top_genres_by_year_pd['genre']]
# 创建3D散点图 - 电影类型
fig_genre = go.Figure(data=[go.Scatter3d(
x=top_genres_by_year_pd['year'],
y=y_genre,
z=top_genres_by_year_pd['count'],
mode='markers',
marker=dict(
size=12,
color=top_genres_by_year_pd['count'], # 设置颜色为电影数量
colorscale='Viridis', # 颜色映射样式
opacity=0.8
)
)])
fig_genre.update_layout(
title='每年上映电影数量最多的前三名电影类型',
scene = dict(
xaxis_title='年份',
yaxis_title='电影类型',
zaxis_title='电影数量'
),
scene_yaxis=dict(tickvals=list(genre_to_index.values()), ticktext=list(genre_to_index.keys()))
)
fig_genre.show()
country_to_index = {country: index for index, country in enumerate(top_countries_by_year_pd['country'].unique())}
y_country = [country_to_index[country] for country in top_countries_by_year_pd['country']]
# 创建3D散点图 - 制片国家/地区
fig_country = go.Figure(data=[go.Scatter3d(
x=top_countries_by_year_pd['year'],
y=y_country,
z=top_countries_by_year_pd['avg_rating'],
mode='markers',
marker=dict(
size=12,
color=top_countries_by_year_pd['avg_rating'],
colorscale='Cividis',
opacity=0.8
)
)])
fig_country.update_layout(
title='每年平均评分前3的制片国家/地区',
scene = dict(
xaxis_title='年份',
yaxis_title='制片国家/地区',
zaxis_title='平均评分'
),
scene_yaxis=dict(tickvals=list(country_to_index.values()), ticktext=list(country_to_index.keys()))
)
fig_country.show()
# 关闭Spark会话
spark.stop()
运行结果:
注意,本题结果大概率是对的,但是老师有个追加的要求,写代码的时候第二题没有对国家地区进行只选第一个的拆分,所以希望各位自行修改,如果不修改,结果会有一点点差异,而且设计成表格形式比较好,当然也可以直接去掉可视化部分,交差是没问题的了。
第七题
第七题也是按照博客的步骤来进行运行:
注意老师百度网盘的包里面包含了Maven包,请安装到指定位置
然后如果用Linux写Java文件不好写可以再Windows写好后传输到VMware虚拟机中
务必注意文件格式,代码林子雨老师博客已给出
运行结果大概如下