python dataframe的某一列变为list_单机用python写spark处理20G的数据

1a340721-b912-eb11-8da9-e4434bdf6706.png

因为机器学习等算法的快速发展,python已经成为重要的开发语言。利用python做数据挖掘时,Pandas、numpy是常见的依赖库,Pandas、nump在本质上是将数据一次性读入内存后再处理。因pc资源,尤其是内存等资源的限制,当数据量变大后,再用上述方法时,可能发生内存不足,或者剩余内存很少,导致无法处理,或者处理速度很慢的情况。hadoop和spark是主流的大数据平台,主流语言是Java和Scala,为应对python的快速发展,spark推出了python版:pyspark。pyspark可以在单机上使用,解决大数据问题。

本文主要从pyspark原理、pyspark常见操作两个角度进行讲解。


pyspark原理

a.以时间换空间进行大数据处理

关键词:shuffle

在Pandas、numpy进行数据处理时,一次性将数据读入内存中,当数据很大时内存溢出,无法处理;同时而且很多执行算法是单线程处理,不能充分利用cpu性能。

spark在中最关键的概念之一是shuffle,他将数据集分成数据块:shuffle。在读取数据时,每个进程(线程)读取一个数据块,轮片将所有的数据处理完,解决了数据量巨大问题,极大的利用了CPU资源。同时,支持分布式结构,弹性拓展硬件资源。

小结:

1:不是将数据一次性全部读入内存中,而是分片,用时间换空间。

2:支持分布式,弹性拓展硬件资源。

  • 个人使用时,完全可以使用standalone模型,进行单机处理。
安装方式:pip install pyspark

a.类sql、类pandas操作方式更易上手

在数据结构上Spark支持dataframe、sql和rdd模型。

Dataframe与pandas很像

C. 速度更快

在pandas中,我们所有的动作都是写完理解执行。spark引入了两个概念:算子和转换。

算子和转换是Spark中最重要的两个动作。算子好比是盖房子中的画图纸,转换是搬砖盖房子。有时候我们做一个统计是多个动作结合的组合拳,spark常将一系列的组合写成算子的组合执行,执行时,spark会对算子进行简化等优化动作,执行速度更快。


pyspark常见操作

关键词:

  1. config("spark.default.parallelism", 3000):设置shuffle个数
  2. read.csv,read.format:读取文件
  3. withColumn:添加一列;withColumn("id", monotonically_increasin):自动插入index
  4. select:选取数据
  5. join:合并
  6. toDF("id:long,day: int"):转换成pyspark的dataframe
  7. persist():持久化
  8. data.schema:表头数据结构
  9. sort_values(by=["日期","小时"],ascending=[1, 1]):排序
  10. data.groupBy("小时","日期").agg({"流量":"sum"})
  11. foreach:apply
  12. repartition(1).write.csv("test/ok",mode="overwrite"):写入硬盘
  13. data.createOrReplaceTempView("plan_AllData"):创造表名
  14. ...

开始spark的快速入门,强烈多看官方原始文档:

Getting Started - Spark 2.4.1 Documentation​spark.apache.org Welcome to Spark Python API Docs!​spark.apache.org
1d340721-b912-eb11-8da9-e4434bdf6706.png

头文件

import 

1.配置

Spark使用时需要对每次都对脚本进行配置,也就是spark代码中进行设置。

spark=SparkSession.builder.config("spark.default.parallelism", 3000).appName("taSpark").getOrCreate()

解释:

A: config("spark.default.parallelism", 3000)

对数据进行切片,专业名词叫shuffle。因为我读取的数据是20g,所以设置成3000份,每次每个进程(线程)读取一个shuffle,避免内存不足的异常。

B: appName("taSpark")

设置程序的名字

2.读文件

参考链接:

pyspark.sql module​spark.apache.org

方法一:

data = spark.read.csv(cc,header=None, inferSchema="true")

方法二

data = spark.read.format(csv).load(cc, header=None, inferSchema="true")

解释:

方法一:

该方法是只读csv格式的文件,其中cc是文件的路径,spark支持list格式,既cc是一个list,每个元素是一个csv文件的路径。

header=None,同pandas,指定表头

inferSchema="true",csv中的数据格式在读取时自动推断。注意,与pandas不同,这个必须要指定,且每个列只是一种数据类型。

查看读取数据的数据类型:data.printSchema()

|-- 用户手机号: long (nullable = true)

|-- 开始时间: integer (nullable = true)

|-- TAI: string (nullable = true)

|-- 次数: integer (nullable = true)

|-- 持续时间: integer (nullable = true)

|-- 流量: long (nullable = true)

|-- 日期: long (nullable = true)

|-- 小时: integer (nullable = true)

修改dataframe的表头,重定义dataframe

data=data.toDF(u"用户手机号",u"开始时间",u"TAI",u"次数",u"持续时间",u"流量")

3、 操作

Spark与Pandas中DataFrame对比(详细)

Spark与Pandas中DataFrame对比(详细) - 宁哥的小站​www.lining0806.com

a: 添加一列数据

方法一:

 # 添加id
 data=data.withColumn("id", monotonically_increasing_id())
 b=data.select(data.id,data["开始时间"].astype("string")).rdd.map(lambda x:[x[0],int(x[1][-4:-2])]).
 toDF("id:long,day: int")
 # 插入列
 data=data.join(b,data.id==b.id)

解释:

因为spark是在每个shuffle中,不能直接插入,要进行类似合表的动作。

思路:

添加index,然后在以index为key,对数据进行合并。

data=data.withColumn("id", monotonically_increasin)

withColumn函数是添加一列数据,但是这个数据必须是原始表中的数据。"id"是新添加列的名称,monotonically_increasin是给每个行一个key,到达添加index的效果。

data.select(data.id,data["开始时间"].astype("string")).rdd.map(lambda x:[x[0],int(x[1][-4:-2])]).toDF("id:long,day: int")

select(data.id,data["开始时间"].astype("string")),从数据中读取id列和“开始时间”列,同时把开始“开始时间”转换成string数据类型。此时的数据类型是dataframe,把他们转成rdd然后操作。Rdd的map是对每一行,每行的数据类型是Row,最后要转换城dataframe要转换成list或者row,本次转换,我们将其转换成list。

toDF("id:long,day: int")

将RDD构建成dataframe,指定列名和数据类型。注意,数据类型要与原始的一致。

缺点:因为join,该方法时间较久。

方法二

使用rdd的map方法,该方法速度快,但是不适合其他表的数据插入。

 # 加入一个表名
 # 保留原始的名字
 StructType = data.schema
 # 添加一个字段
 StructType.add(StructField("日期", LongType()))
 StructType.add(StructField("小时", IntegerType()))
 def f(x):
 xtmp=list(x.asDict().values())
 c=int(str(x["开始时间"])[-4:-2])
 xtmp.append(c)
 c=int(str(x["开始时间"])[-2:])
 xtmp.append(c)
 
 return xtmp
 pass
 datardd=data.rdd.map(f)
 data=spark.createDataFrame(datardd,StructType)

b: 修改一列数据:

# 日期替换成星期
 placedict = {24: 7, 25: 1, 26: 2, 27: 3, 28: 4, 29: 5, 30: 6}
 def f(x):
 x=x.asDict()
 try:
 x['日期']=placedict[x['日期']]
 pass
 except:
 x['日期']=-1
 pass
 return list(x.values())
 pass
 # 保存原来的头
 StructType = data.schema
 # 转换
 datardd = data.rdd.map(f)
 # 转换完成
 data = spark.createDataFrame(datardd, StructType)

c: 统计

1. c=data.groupby(["小时","日期","用户手机号"]).count().groupBy("小时","日期").count().toPandas()

2. c=c.sort_values(by=["日期","小时"])

3. a=data.groupBy("小时","日期").agg({"流量":"sum"})

4. e=e.withColumn("avg(sum(流量))", e["avg(sum(流量))"]/(1024*1024)).rderBy(["日期", "小时"], ascending=[1, 1]).toPandas()

5. data.foreach(lambda x: int(str(x["开始时间"])[-4:-2]))

groupby与pandas一致

sort_values降序排列,ascending=[1, 1],设置某列是升序还是降序

agg({"流量":"sum"}),因为shuffle比较多,每次历遍都很繁琐,所以可以对特定列做特定的动作。

data.foreach(lambda x: int(str(x["开始时间"])[-4:-2])),与pandas的apply一样。

持久化

d: 做一次持久化

算子每次都要从头开始执行,有时候很多动作是重发的,也就是起始点是一样的,因此可以做一个持久化,也就是把动作提前做完,保存好生成的数据。包括cache和presist,其中cache是把数据保存在内存,不推荐。Persist与read类似,推荐。

e: 写入

data.repartition(1).write.csv("test/ok",mode="overwrite")

写入是写入一个文件中,其中repartition(1)是告诉写入的文件个数,默认是与shuffle个数相同,可以不用这个参数。

4、 SQL模式

# sql

#创造表名

data.createOrReplaceTempView("plan_AllData")
# 获取最大最小值
longitudeMAX_MIN=spark.sql("SELECT MAX(longitude),MIN(longitude) FROM plan_AllData").collect()
latitudeMAX_MIN=spark.sql("SELECT MAX(latitude),MIN(latitude) FROM plan_AllData").collect()

与使用sql相同,返回的是dataframe结构的数据

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值