语言:python
工具:PyCharm、Hadoop集群、spark集群
1.准备数据
下载数据
下载地址,下载u.data,下载后可以用记事本打开查看里面内容(10w条记录)。
记事本内没有标出每一列的含义,可以参考下图。
上传数据
将下载好的u.data上传到Linux主机/data目录下
2.编写python文件
导入模块
SparkSession
是PySpark中的一个主要入口点,用于创建和管理Spark应用程序的上下文。functions
模块是PySpark中的一个子模块,提供了许多用于数据处理和转换的函数,例如聚合、过滤、排序等。StructType
是PySpark中用于定义结构化数据模式的类,用于指定DataFrame中的列名和数据类型。StringType
是PySpark中的一种数据类型,表示字符串类型的数据。IntegerType
是PySpark中的一种数据类型,表示整数类型的数据。
from pyspark.sql import SparkSession,functions
from pyspark.sql.types import StructType, StringType,IntegerType
创建SparkSession对象
SparkSession.builder
: 是用于构建SparkSession对象的构建器。appName('test')
: 是设置Spark应用程序的名称,可以根据需要进行更改。master("local[*]")
: 是设置Spark应用程序的主节点地址。在这里,"local[*]"表示在本地运行Spark应用程序,使用所有可用的CPU核心。getOrCreate()
: 是获取或创建SparkSession对象的方法。如果已经存在一个SparkSession对象,则返回该对象;否则,将创建一个新的SparkSession对象。
spark = SparkSession.builder.appName('test'). master("local[*]"). getOrCreate()
创建SparkContext对象
- SparkContext是Spark的主要入口点,用于与集群通信并创建RDD(弹性分布式数据集)。通过SparkContext,可以执行各种Spark操作,如读取数据、转换数据和执行操作。
sc = spark.sparkContext
定义Spark DataFrame中的schema
StructType()
:创建一个空的结构类型,用于存储字段信息。add("user_id", StringType(), nullable=True)
:向结构类型中添加一个名为"user_id"的字段,字段类型为StringType(),可为空。add("movie_id", IntegerType(), nullable=True)
:向结构类型中添加一个名为"movie_id"的字段,字段类型为IntegerType(),可为空。add("rank", IntegerType(), nullable=True)
:向结构类型中添加一个名为"rank"的字段,字段类型为IntegerType(),可为空。add("marktime", StringType(), nullable=True)
:向结构类型中添加一个名为"marktime"的字段,字段类型为StringType(),可为空。
schema = StructType().add("user_id", StringType(), nullable=True).add("movie_id", IntegerType(), nullable=True).add("rank", IntegerType(), nullable=True).add("marktime", StringType(), nullable=True)
读取数据文件
spark.read.format('csv')
:使用Spark的CSV数据源读取数据。.option("sep", "\t")
:设置分隔符为制表符("\t")。.option("header", False)
:设置文件中没有标题行。.option("encoding", "utf-8")
:设置文件编码为UTF-8。.schema(schema=schema)
:指定数据的模式(schema),其中schema
是预先定义好的模式。.load("
file:///data/u.data")
:加载指定路径下的文件。
df = spark.read.format('csv').option("sep", "\t"). option("header", False).option("encoding", "utf-8").schema(schema=schema).load("file:///data/u.data")
测试
目前完整代码如下,只是为了测试能否读取u.data文件
import findspark
findspark.init()
from pyspark.sql import SparkSession,functions
from pyspark.sql.types import StructType, StringType,IntegerType
if __name__=='__main__':
spark = SparkSession.builder.appName('test'). master("local[*]"). getOrCreate()
sc = spark.sparkContext
schema = StructType().add("user_id", StringType(), nullable=True).add("movie_id", IntegerType(), nullable=True).add("rank", IntegerType(), nullable=True).add("marktime", StringType(), nullable=True)
df = spark.read.format('csv').option("sep", "\t"). option("header", False).option("encoding", "utf-8").schema(schema=schema).load("file:///data/u.data")
df.show()
3.数据统计
一、求同一用户打过所有分的平均分
- groupby("user_id"):根据"userid"列对DataFrame进行分组
-
avg("rank"):计算每个组中"rank"列的平均值
-
withColumnRenamed("avg(rank)","avg_rank"):将计算结果的列名从"avg(rank)"改为"avg_rank"
- withColumn("avg_rank",functions.round("avg_rank",2)) :将"avg_rank"列的值保留两位小数
-
orderBy("avg_rank",ascending=False):按照"avg_rank"列的值降序排序
-
show():打印结果
df.groupby("user_id").avg("rank").withColumnRenamed("avg(rank)","avg_rank").withColumn("avg_rank",functions.round("avg_rank",2)).orderBy("avg_rank",ascending=False).show()
运行结果(部分):
二、求电影的平均分
- df.createTempView("movie"):它创建了一个名为"movie"的临时视图,该视图可以用于查询。
- spark.sql("""XXX......""):表示执行SQL查询语句
- round(avg(rank),2) as avg_rank:将平均数rank保留2位小数,同时更名为avg_rank
- SQL语句:从movie中查询movie_id和avg_rank,并按movie_id分组,按avg_rank的值降序排序
df.createTempView("movie")
spark.sql("""select movie_id,round(avg(rank),2) as avg_rank from movie group by movie_id order by avg_rank desc""").show()
运行结果(部分):
三、查询大于平均分的电影的数量
- df是一个 DataFrame 对象
- where(): 用于筛选出 满足条件的行
- df["rank"] > df.select(functions.avg("rank")).first()["avg(rank)"]:即 rank列的值大于 rank列的平均值。
- df.select(functions.avg("rank")).first()["avg(rank)"]:select方法类似SQL的查询,使用functions.avg()函数计算 rank列的平均值。first()["avg(rank)"]方法:select查询后返回一行数据,需要访问第一行数据,并访问该行数据中 avg(rank)列的值。
- count():计算满足条件的行数,并将结果打印出来。
print(df.where(df["rank"]>df.select(functions.avg("rank")).first()["avg(rank)"]).count())
运行结果:
四、查询在电影评分>3的电影中,打分次数最多的用户,其打分的平均分
第一行代码:
- df.where("rank > 3"):选择rank大于3的记录
- groupBy("user_id").count():按照用户ID进行分组计数
- withColumnRenamed('count','cnt'):将计数结果的列名改为cnt
- orderBy("cnt",ascending=False):按照计数结果降序排序
- limit(1).first()["user_id"]:取出计数最多的用户ID
第二行代码:
- df.filter(df["user_id"]==user_id):筛选出user_id等于user_id值的行
-
select(functions.round(functions.avg("rank"),2)):计算这些行中rank列的平均值,并将结果保留两位小数
user_id=df.where("rank > 3").groupBy("user_id").count().withColumnRenamed('count','cnt').orderBy("cnt",ascending=False).limit(1).first()["user_id"]
df.filter(df["user_id"]==user_id).select(functions.round(functions.avg("rank"),2)).show()
运行结果:
五、查询每个用户的平均打分,最低打分,最高打分
- df.groupby("user_id"): 据user_id列对进行分组
- agg():对分组后的数据进行聚合操作,可以对每个分组进行多个聚合操作,例如计算平均值、最小值、最大值等。
- functions.round(functions.avg("rank"),2).alias("avg_rank"):求平均分,保留2位小数,并指定名字为avg_rank
- functions.min("rank").alias("min_rank"):求最低分,并指定名字为min_rank
- functions.max("rank").alias("max_rank"):求最高分,并指定名字为max_rank
df.groupby("user_id").agg(functions.round(functions.avg("rank"),2).alias("avg_rank"),functions.min("rank").alias("min_rank"),functions.max("rank").alias("max_rank")).show()
运行结果(部分):
六、查询评分超过100次的电影的平均分、排名、Top10
- df.groupby("movie_id"):根据movie_id经行分组
- agg():对分组后的数据进行聚合操作,可以对每个分组进行多个聚合操作,例如计算平均值、最小值、最大值等。
- functions.count("movie_id").alias("cnt"):统计相同movie_id的数量,命名为cnt
- functions.round(functions.avg("rank"),2).alias("avg_rank"):求平均分,保留2位小数,并指定名字为avg_rank
- where("cnt>100"):筛选出评分超过100次的电影
- orderBy("avg_rank",ascending=False):根据avg_rank降序排序
- imit(10).show():只显示前10个数据
df.groupby("movie_id").agg(functions.count("movie_id").alias("cnt"),functions.round(functions.avg("rank"),2).alias("avg_rank")).where("cnt>100").orderBy("avg_rank",ascending=False).limit(10).show()
运行结果:
4.完整代码
import findspark
findspark.init()
from pyspark.sql import SparkSession,functions
from pyspark.sql.types import StructType, StringType,IntegerType
if __name__=='__main__':
spark = SparkSession.builder.appName('test'). master("local[*]"). getOrCreate()
sc = spark.sparkContext
schema = StructType().add("user_id", StringType(), nullable=True).add("movie_id", IntegerType(), nullable=True).add("rank", IntegerType(), nullable=True).add("marktime", StringType(), nullable=True)
df = spark.read.format('csv').option("sep", "\t"). option("header", False).option("encoding", "utf-8").schema(schema=schema).load("file:///data/u.data")
#文件读取测试
#df.show()
#求同一用户打过所有分的平均分
#df.groupby("user_id").avg("rank").withColumnRenamed("avg(rank)","avg_rank").withColumn("avg_rank",functions.round("avg_rank",2)).orderBy("avg_rank",ascending=False).show()
#求电影的平均分
#df.createTempView("movie")
#spark.sql("""select movie_id,round(avg(rank),2) as avg_rank from movie group by movie_id order by avg_rank desc""").show()
#查询大于平均分的电影的数量
#print(df.where(df["rank"]>df.select(functions.avg("rank")).first()["avg(rank)"]).count())
#查询在电影评分>3的电影中,打分次数最多的用户,其打分的平均分
#user_id=df.where("rank > 3").groupBy("user_id").count().withColumnRenamed('count','cnt').orderBy("cnt",ascending=False).limit(1).first()["user_id"]
#df.filter(df["user_id"]==user_id).select(functions.round(functions.avg("rank"),2)).show()
#查询每个用户的平均打分,最低打分,最高打分
#df.groupby("user_id").agg(functions.round(functions.avg("rank"),2).alias("avg_rank"),functions.min("rank").alias("min_rank"),functions.max("rank").alias("max_rank")).show()
#查询评分超过100次的电影的平均分、排名、Top10
#df.groupby("movie_id").agg(functions.count("movie_id").alias("cnt"),functions.round(functions.avg("rank"),2).alias("avg_rank")).where("cnt>100").orderBy("avg_rank",ascending=False).limit(10).show()