本项目基于Linux环境下进行数据分析,利用大数据所学知识(Hadoop生态系统组件,如Hadoop、Hive、Spark等)以及大数据相关知识,实现“世界杯数据分析”项目。在此项目完成过程中,我们通过自己数据分析探索能力发挥想象力,一共采取了数据预处理、分析及可视化三个步骤对该项目的三个数据集进行处理分析。在此期间,我们对spark、hadoop等大数据处理与分析框架的使用有了更进一步的理解,更加熟练地掌握hive数据仓库的管理与应用,能对SQL查询语句和hive查询语句更加熟练地运用。
最后希望大家也能在此博文中有所收获,废话不多说,上干货!
前置说明
项目环境:anaconda3.8(Linux)、pycharm专业版(用于远程连接Linux进行开发)、xhell、xftp、hive、Hadoop、spark
上述环境都是大数据主流框架和工具,最好可以自己独立搭一遍环境,需要pycharm专业版破解和整个环境或源码可以私信博主(回复较慢,请见谅)
数据源:FIFA官方提供的世界杯相关数据
数据字段说明
1、世界杯成绩信息表:WorldCupsSummary
包含了所有21届世界杯赛事(1930-2018)的比赛主办国、前四名队伍、总参赛队伍、总进球数、现场观众人数等汇
总信息,包括如下字段:
Year:举办年份
HostCountry:举办国家
Winner:冠军队伍
Second:亚军队伍
季军队伍Third:
Fourth:第四名队伍
GoalsScored:总进球数
QualifiedTeams:总参赛队伍数
MatchesPlayed:总比赛场数
Attendance:现场观众总人数
HostContinent:举办国所在洲
WinnerContinent:冠军国家队所在洲
2、世界杯比赛比分汇总表:WorldCupMatches.csv包含了所有21届世界杯赛事(1930-2014)单场比赛的信息,包括比赛时间、比赛主客队、比赛进球数、比赛裁判等信息。包括如下字段:
Year:比赛(所属世界杯)举办年份
Datetime:比赛具体日期
Stage:比赛所属阶段,包括 小组赛(GroupX)、16进8(Quarter-Fina1)、半决赛(Semi-Fina1)、决赛(Final)等
Stadium:比赛体育场
City:比赛举办城市
Home Team Name:主队
Away Team Name:客队名
Home Team Goals:主队进球数
Away Team Goals:客队进球数
Attendance:现场观众数
Half-time Home Goals:上半场主队进球数
Half-time Away Goals:上半场客队进球数
Referee:主裁
Assistant1:助理裁判1
Assistant 2:助理裁判2
RoundID:比赛所处阶段ID,和Stage字段对应
MatchID:比赛ID
Home Team Initials:主队名字缩写
Away Team Initials:客队名字缩写
3、世界杯球员信息表:WorldCupPlayers.csv
RoundID:比赛所处阶段ID,同比赛信息表的RoundID字段
MatchID:比赛ID
Team Initials:队伍名
Coach Name:教练名
Line-up:首发/替补
Shirt Number:球衣号码Player Name:队员名Position:比赛角色,包括:C=Captain,GK=Goalkeeper比赛事件,包括进球、红/黄牌等
整体数据源、源码、环境情况如下:
第一步 环境搭建和启动
先将搭建好的环境启动起来:Hadoop集群、spark集群、hive元数据服务
启动命令:(根据自己路径替换,如果没有脚本,就不能一键启动,要挨个启动)
/usr/local/hadoop-3.1.4/sbin/start-all.sh
/usr/local/spark-3.2.1-bin-hadoop2.7/sbin/start-all.sh
hive --service metastore &
启动后通过jps查看进程,以下为全部需要用到的服务
第二步 数据迁移
导入数据
将原始数据文件csv下载至本地并上传到Linux的指定目录下。
使用Hive建立好对应表结构的数据表。创建表HQL语句:
三张表的 Hive SQL 创建语句:
1. 世界杯成绩信息表 (WorldCupsSummary)worldcupssummary
sql
CREATE TABLE IF NOT EXISTS WorldCupsSummary (
Year INT,
HostCountry STRING,
Winner STRING,
Second STRING,
Third STRING,
Fourth STRING,
GoalsScored INT,
QualifiedTeams INT,
MatchesPlayed INT,
Attendance INT,
HostContinent STRING,
WinnerContinent STRING
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS TEXTFILE;
2. 世界杯比赛比分汇总表 (WorldCupMatches)worldcupmatches
sql
CREATE TABLE IF NOT EXISTS WorldCupMatches (
Year INT,
Datetime STRING,
Stage STRING,
Stadium STRING,
City STRING,
HomeTeamName STRING,
AwayTeamName STRING,
HomeTeamGoals INT,
AwayTeamGoals INT,
Attendance INT,
HalfTimeHomeGoals INT,
HalfTimeAwayGoals INT,
Referee STRING,
Assistant1 STRING,
Assistant2 STRING,
RoundID INT,
MatchID INT,
HomeTeamInitials STRING,
AwayTeamInitials STRING
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS TEXTFILE;
3. 世界杯球员信息表 (WorldCupPlayers)worldcupplayers
sql
CREATE TABLE IF NOT EXISTS WorldCupPlayers (
RoundID INT,
MatchID INT,
TeamInitials STRING,
CoachName STRING,
Lineup STRING,
ShirtNumber INT,
PlayerName STRING,
Position STRING,
Event STRING
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
STORED AS TEXTFILE;
上传Linux本地原始数据到hdfs上。
命令:hdfs dfs -put /data/sjb/* /user/sjb data
加载hdfs原始数据到hive表中。命令:
load data inpath '/user/sjb_data/WorldCupMatches.csv' into table worldcupmatches;
load data inpath '/user/sjb_data/WorldCupPlayers.csv' into table worldcupplayers;
load data inpath '/user/sjb_data/WorldCupsSummary.csv' into table worldcupssummary;
验证结果查看行数。
第三步 数据预处理
为了提高运算效率,我们选用pyspark进行后面的数据处理和分析。
使用pycharm远程连接Linux里的python进行远程开发,并用pyspark对hive表进行操作。远程连接配置教程参考请点击(只有pycharm专业版才可以远程连接开发)
1.初始化spark 创建 SparkSession
# 创建 SparkSession
spark = SparkSession.builder \
.appName("Handle Missing, Duplicates, and Standardize Formats") \
.config("hive.metastore.uris", "thrift://192.168.128.130:9083") \
.enableHiveSupport() \
.getOrCreate()
2.数据预处理 运行结果:
世界杯成绩信息表 (WorldCupsSummary)
世界杯比赛比分汇总表 (WorldCupMatches)
世界杯球员信息表 (WorldCupPlayers)
将数据清洗后的三个dataframe对象分别写入三个新表中。
运行结果展示:
数据预处理完整代码实现:
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, to_date
# 创建 SparkSession
spark = SparkSession.builder \
.appName("Handle Missing, Duplicates, and Standardize Formats") \
.config("hive.metastore.uris", "thrift://192.168.128.130:9083") \
.enableHiveSupport() \
.getOrCreate()
# 使用 sjb 数据库
spark.sql("use sjb")
# 定义三个表的名称
table_names = ["worldcupmatches", "worldcupplayers", "worldcupssummary"]
# 循环处理每个表
for table_name in table_names:
# 从 SQL 查询中读取数据
df = spark.sql(f"SELECT * FROM {table_name}")
# 显示 DataFrame 的 schema 和前几行数据
print(f"Schema of {table_name}:")
df.printSchema()
print(f"First 5 rows of {table_name}:")
df.show(5, truncate=False)
# 处理缺失值(数值类型列)
numeric_cols = [c for c, dtype in df.dtypes if dtype != "string" and c != "datetime"]
if numeric_cols:
# 计算每列的缺失值数量
missing_counts = df.select([col(c).isNull().cast("int").alias(c) for c in df.columns]) \
.toDF(*df.columns)
print(f"Missing value counts for {table_name}:")
missing_counts.show()
# 零填充缺失值
for col_name in numeric_cols:
df = df.withColumn(col_name, col(col_name).cast("double")).fillna(0, subset=[col_name])
print(f"DataFrame after filling missing values for {table_name}:")
df.show(truncate=False)
else:
print(f"No numeric columns found in {table_name}. Skipping imputation.")
'''
# 处理日期格式
date_columns = [c for c, dtype in df.dtypes if dtype == "string" and "date" in c.lower()]
for col_name in date_columns:
df = df.withColumn(col_name, to_date(col(col_name), "yyyy-MM-dd"))
'''
# 处理重复值
df = df.dropDuplicates()
print(f"处理重复值后的 DataFrame {table_name}:")
df.show(truncate=False)
# 显示标准化后的 DataFrame
print(f"标准化格式后的 DataFrame为表 {table_name}:")
df.show(truncate=False)
# 将处理后的 DataFrame 写入新表中
new_table_name = f"{table_name}_processed"
df.write.mode("overwrite").saveAsTable(new_table_name)
print(f"保存处理后的 DataFrame 为表: {new_table_name}")
# 停止 SparkSession
spark.stop()
第四步 数据分析与可视化
汇总统计
统计比赛总场次、总进球数、总参赛队伍数、总观众人数,具体代码实现如下:
统计结果:
统计哪些国家举办过世界杯,具体代码实现:
统计结果展示:
比赛结果分析
统计进入半决赛的国家次数,夺冠次数,获得亚军次数,获得季军次数次数,代码实现如下:
统计结果展示:
比赛结果分析
统计过去21届世界杯中比分差距最大的十场比赛,并用直方图展示:
比赛结果分析完整代码实现:
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, expr, count
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams['axes.unicode_minus'] = False
# 创建 SparkSession
spark = SparkSession.builder \
.appName("World Cup Data Analysis") \
.config("hive.metastore.uris", "thrift://192.168.128.130:9083") \
.enableHiveSupport() \
.getOrCreate()
# 使用数据库
spark.sql("use sjb")
# 读取世界杯成绩信息表
df_summary = spark.table("worldcupssummary_processed")
# 读取世界杯比赛比分汇总表
df_matches = spark.table("worldcupmatches_processed")
# 统计进入半决赛的国家次数
semifinalists_count = df_summary.select(col("Winner").alias("Country")).union(
df_summary.select(col("Second").alias("Country"))).union(
df_summary.select(col("Third").alias("Country"))).union(
df_summary.select(col("Fourth").alias("Country"))) \
.groupBy("Country").agg(count("*").alias("Count")).orderBy(col("Count").desc())
# 统计夺冠次数、获得亚军次数和获得季军次数
winner_count = df_summary.groupBy("Winner").agg(count("*").alias("Wins")).orderBy(col("Wins").desc())
runner_up_count = df_summary.groupBy("Second").agg(count("*").alias("RunnerUps")).orderBy(col("RunnerUps").desc())
third_place_count = df_summary.groupBy("Third").agg(count("*").alias("ThirdPlaces")).orderBy(col("ThirdPlaces").desc())
# 显示结果
print("进入半决赛的国家次数:")
semifinalists_count.show()
print("夺冠次数:")
winner_count.show()
print("获得亚军次数:")
runner_up_count.show()
print("获得季军次数:")
third_place_count.show()
# 计算比分差距并选择前10场比赛
top_goal_diff = df_matches.withColumn("ScoreDifference", expr("abs(hometeamgoals - awayteamgoals)")) \
.orderBy(col("ScoreDifference").desc()) \
.limit(10)
# 将结果转换为 Pandas DataFrame,并显示
top_goal_diff_pandas = top_goal_diff.toPandas()
# 绘制直方图展示比分差距最大的十场比赛
plt.figure(figsize=(12, 8))
ax = sns.barplot(y=top_goal_diff_pandas['hometeamname'] + ' VS ' + top_goal_diff_pandas['awayteamname'],
x='ScoreDifference', data=top_goal_diff_pandas, palette='viridis')
plt.xlabel('比分差距', fontsize=12)
plt.ylabel('比赛', fontsize=12)
plt.title('比分差距最大的十场比赛', fontsize=14)
plt.xticks(fontsize=10)
plt.yticks(fontsize=10)
# 在图上添加额外信息(例如比赛日期和比分)
for i, row in top_goal_diff_pandas.iterrows():
text = f"日期: {row['datetime']}, 比分: {row['hometeamgoals']}-{row['awayteamgoals']}"
ax.text(0.5, i, text, fontsize=10, color='white', va='center')
plt.show()
# 停止 SparkSession
spark.stop()
进球数分析
统计场均进球数。分析上半场与下半场进球数分布情况并通过散点图进行可视化展示,具体代码实现如下:
统计结果分析:
可视化结果展示:
进球数分析完整代码实现:
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, sum
import matplotlib.pyplot as plt
import seaborn as sns
import matplotlib
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams['axes.unicode_minus'] = False
# 创建 SparkSession
spark = SparkSession.builder \
.appName("World Cup Data Exploration") \
.config("hive.metastore.uris", "thrift://192.168.128.130:9083") \
.enableHiveSupport() \
.getOrCreate()
# 使用数据库
spark.sql("use sjb")
# 读取世界杯比赛比分汇总表
df_matches = spark.table("WorldCupMatches_processed")
# 统计总进球数和比赛场数
total_goals = df_matches.select(sum(col("HomeTeamGoals") +
col("AwayTeamGoals")).alias("TotalGoals")).collect()[0]["TotalGoals"]
total_matches = df_matches.count()
# 计算场均进球数
average_goals_per_match = total_goals / total_matches
print(f"场均进球数: {average_goals_per_match}")
# 统计上半场和全场进球数
goals_data = df_matches.select(col("HalfTimeHomeGoals").alias("HTHomeGoals"),
col("HalfTimeAwayGoals").alias("HTAwayGoals"),
col("HomeTeamGoals").alias("FTHomeGoals"),
col("AwayTeamGoals").alias("FTAwayGoals")).toPandas()
# 绘制散点图比较进球数分布
plt.figure(figsize=(12, 8))
plt.scatter(goals_data["HTHomeGoals"], goals_data["HTAwayGoals"], label="上半场进球数")
plt.scatter(goals_data["FTHomeGoals"], goals_data["FTAwayGoals"], label="全场进球数")
plt.title('世界杯进球数分布比较')
plt.xlabel('主队进球数')
plt.ylabel('客队进球数')
plt.legend()
plt.grid(True)
plt.tight_layout()
# 显示图形
plt.show()
# 停止 SparkSession
spark.stop()
观众人数分析
统计不同国家、不同年份的观众人数,找出观众数最多的比赛场次,具体代码实现:
统计结果展示:
分析过去21届世界杯现场观众数量的变化并使用折线图进行可视化展示,具体代码实现如下:
可视化结果展示:
观众人数分析完整代码实现:
# 导入必要的库
from pyspark.sql import SparkSession
from pyspark.sql.functions import col
import matplotlib.pyplot as plt
import matplotlib
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams['axes.unicode_minus'] = False
# 创建 SparkSession
spark = SparkSession.builder \
.appName("World Cup Data Exploration") \
.config("hive.metastore.uris", "thrift://192.168.128.130:9083") \
.enableHiveSupport() \
.getOrCreate()
# 使用数据库
spark.sql("use sjb")
# 计算进球差距并选择前10场比赛
df_matches = spark.table("worldcupmatches_processed")
# 找出观众人数最多的比赛
most_attendance_matches = df_matches.orderBy(col("Attendance").desc()).limit(10)
most_attendance_matches.show()
# 按年份计算总观众人数
attendance_by_year = df_matches.groupBy("Year").agg({"Attendance": "sum"}).orderBy("Year")
# 将Spark DataFrame转换为Pandas DataFrame以便后续使用Matplotlib绘图
attendance_pd = attendance_by_year.toPandas()
# 绘制折线图
plt.figure(figsize=(10, 6))
plt.plot(attendance_pd["Year"], attendance_pd["sum(Attendance)"], marker='o', linestyle='-')
plt.title('世界杯观众人数变化 (1930-2014)')
plt.xlabel('Year')
plt.ylabel('观众总数')
plt.grid(True)
plt.xticks(attendance_pd["Year"], rotation=45)
plt.tight_layout()
plt.xlim(1930, 2014)
# 显示图形
plt.show()
# 停止 SparkSession
spark.stop()
球员表现分析
统计不同年份夺冠队伍每个球员的进球、被罚红黄牌数量,分析明星球员的表现。,具体代码实现如下:
统计结果展示:
球员表现分析完整代码实现:
# 导入必要的库
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, substring, when, count
# 设置 Python 执行路径(如果需要的话)
import os
os.environ["PYSPARK_PYTHON"] = "/opt/anaconda3/bin/python3"
# 创建 SparkSession
spark = SparkSession.builder \
.appName("World Cup Data Exploration") \
.config("hive.metastore.uris", "thrift://192.168.128.130:9083") \
.enableHiveSupport() \
.getOrCreate()
# 使用数据库
spark.sql("use sjb")
# 加载并显示数据
df_players = spark.table("worldcupplayers_processed")
# 统计每个球员的进球数
goals_per_player = df_players \
.filter(substring(col("playername"), 1, 1) == "G") \
.groupBy("playername") \
.agg(count("*").alias("goals")) \
.orderBy("goals", ascending=False)
goals_per_player.show()
# 统计每个球员的红黄牌数
cards_per_player = df_players \
.filter((substring(col("playername"), 1, 1) == "Y") |
(substring(col("playername"), 1, 1) == "R")) \
.groupBy("playername", "event") \
.agg(count("*").alias("count"))
cards_per_player.show()
# 停止 SparkSession
spark.stop()
主裁分析
统计参与3届世界杯以上的主裁,具体代码实现如下:
统计结果展示:
主裁分析完整代码实现:
# 导入必要的库
from pyspark.sql import SparkSession
from pyspark.sql.functions import col, substring, when, count
# 设置 Python 执行路径(如果需要的话)
import os
os.environ["PYSPARK_PYTHON"] = "/opt/anaconda3/bin/python3"
# 创建 SparkSession
spark = SparkSession.builder \
.appName("World Cup Data Exploration") \
.config("hive.metastore.uris", "thrift://192.168.128.130:9083") \
.enableHiveSupport() \
.getOrCreate()
# 使用数据库
spark.sql("use sjb")
# 加载并显示数据
df_players = spark.table("worldcupplayers_processed")
# 统计每个球员的进球数
goals_per_player = df_players \
.filter(substring(col("playername"), 1, 1) == "G") \
.groupBy("playername") \
.agg(count("*").alias("goals")) \
.orderBy("goals", ascending=False)
goals_per_player.show()
# 统计每个球员的红黄牌数
cards_per_player = df_players \
.filter((substring(col("playername"), 1, 1) == "Y") |
(substring(col("playername"), 1, 1) == "R")) \
.groupBy("playername", "event") \
.agg(count("*").alias("count"))
cards_per_player.show()
# 停止 SparkSession
spark.stop()
项目成果
比分差距Top直方图
世界杯进球数分布散点图
世界杯观众人数变化折线图
本项目所分析的数据以及可视化产物也许能为体育管理以及球迷研究等领域提供了有价值的数据洞察和决策支持。然而,项目的局限性在于数据的完整性和时效性,某些数据可能受到限制或更新不及时,需要进一步的数据验证和更新。
本项目只做教学示范,不构成投资建议,如需要源码和实验环境可私信博主,回复较慢不常看博客,希望耐心看完此博客的人都有所收获,谢谢