pyspark使用方法

匿名 (未验证) 提交于 2019-12-03 00:22:01

来源,官网spark2.2.1版本
pyspark不同函数的形象化解释
SparkSession是Spark 2.0引入的新概念。SparkSession为用户提供了统一的切入点,来让用户学习spark的各项功能。 在spark的早期版本中,SparkContext是spark的主要切入点,由于RDD是主要的API,我们通过sparkcontext来创建和操作RDD。对于每个其他的API,我们需要使用不同的context。例如,对于Streming,我们需要使用StreamingContext;对于sql,使用sqlContext;对于hive,使用hiveContext。但是随着DataSet和DataFrame的API逐渐成为标准的API,就需要为他们建立接入点。所以在spark2.0中,引入SparkSession作为DataSet和DataFrame API的切入点。SparkSession实质上是SQLContext和HiveContext的组合(未来可能还会加上StreamingContext),所以在SQLContext和HiveContext上可用的API在SparkSession上同样是可以使用的。SparkSession内部封装了SparkContext,所以计算实际上是由SparkContext完成的。

1、pyspark函数接口

pyspark.SparkConf()

是对spark应用进行设置的类

pyspark.SparkContext()


SparkContext.broadcast(value)函数:广播变量


通过在一个变量v上调用SparkContext.broadcast(v)可以创建广播变量。广播变量是围绕着v的封装,可以通过value方法访问这个变量。举例如下:

from pyspark import SparkContext from numpy import array sc=SparkContext() broadcast_var= sc.broadcast(array([1,2,3,4])) print(broadcast_var.value) #运行结果 [1 2 3 4]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

在创建了广播变量之后,在集群上的所有函数中应该使用它来替代使用v.这样v就不会不止一次地在节点之间传输了。另外,为了确保所有的节点获得相同的变量,对象v在被广播之后就不应该再修改。

SparkContext.parallelize(c,numSlice=none)

将一个本地的python对象集群分布以创建一个RDD。如果是将一个范围实现RDD化,推荐使用xrange(),xrange与range的区别在于xrange是生成一个列表对象,而不是列表本身,因而不需要一上来就开辟一块内存区域,但是python3已经没有xrange了。

sc=SparkContext() print(sc.parallelize([1,2,3,4,5,6],3).glom().collect()) print(sc.parallelize([0,6,2],5).glom().collect())
  • 1
  • 2
  • 3

结果如下:

[[1, 2], [3, 4], [5, 6]] [[], [0], [], [6], [2]]
  • 1
  • 2


同时可以看到,如果元素个数少于分区数,则会产生空的列表。

SparkContext.range(start,end=none,step=1,numSlice=none)

产生某个范围内元素组成的RDD

sc=SparkContext() print(sc.range(1,7,2).collect())
  • 1
  • 2

结果如下:

[1, 3, 5]
  • 1

SparkContext.textFile(name, minPartitions=None, use_unicode=True)

从hdfs上,从本地等读取txt文件,并转换成RDD

SparkContext.wholeTextFiles(path, minPartitions=None, use_unicode=True)

读取整个文件夹下的txt文件

SparkContext.union(rdds)

将不同的RDD组合在一起

rdd.map(f)


比如使用map实现(key,values)操作:

#我们首先创建这样的一个rdd input_data=sc.parallelize([['a',1],['b',2],['b',3],['c',4],['a',5],['b',6]],2) #查看结果: print(input_data.glom().collect()) #结果如下: #[[['a', 1], ['b', 2], ['b', 3]], [['c', 4], ['a', 5], ['b', 6]]] #可以看到这样rdd有2个分区,每个分区中包含3个元素,每个元素均为一个列表 #我们假如第一个是键,第二个是值,下面我们来构造键值对rdd,并对每个键进行求和。 #首先利用map(f)构造键值对 input_key_value=input_data.map(lambda x:(x[0],x[1])) #查看一下结果: #[[('a', 1), ('b', 2), ('b', 3)], [('c', 4), ('a', 5), ('b', 6)]] #从上面的结果可以看到,分区未发生变化。但每个元素的形式发生了变化 #下面利用reduceByKey(f)来求和 sum_value=input_key_value.reduceByKey(lambda x,y:x+y) #上式中lambda传入的参数x,y代表元素的值两两间进行,返回x+y表示两两求和,按键逐步聚合。 print(sum_value.glom().collect()) #结果如下: #[[('c', 4), ('b', 11)], [('a', 6)]] #上面的结果比较有意思的是,求reduceByKey求和后,仍然是两个分区。很显示这样存在分区间的数据传递。所以从效率的角度考虑这样的分区方式并不合理。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

下面用map实现函数映射,这里以kmeans为例.代码主体来源网上。

#生成多类单标签数据集 import numpy as np import matplotlib.pyplot as plt from sklearn.datasets.samples_generator import make_blobs center=[[1,1],[-1,-1],[1,-1]] cluster_std=0.3 X,labels=make_blobs(n_samples=200,centers=center,n_features=2,                     cluster_std=cluster_std,random_state=0) print('X.shape',X.shape) print("labels",set(labels))  unique_lables=set(labels) colors=plt.cm.Spectral(np.linspace(0,1,len(unique_lables))) for k,col in zip(unique_lables,colors):     x_k=X[labels==k]     plt.plot(x_k[:,0],x_k[:,1],'o',markerfacecolor=col,markeredgecolor="k",              markersize=14) plt.title('data by make_blob()') plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19






下面是基于map和reduceByKey完成的kmeans聚类

#生成多类单标签数据集 import numpy as np import matplotlib.pyplot as plt from sklearn.datasets.samples_generator import make_blobs center=[[1,1],[-1,-1],[1,-1]] cluster_std=0.3 X,labels=make_blobs(n_samples=200,centers=center,n_features=2,                     cluster_std=cluster_std,random_state=0) # print('X.shape',X.shape) # print("labels",set(labels)) # unique_lables=set(labels) colors=plt.cm.Spectral(np.linspace(0,1,len(unique_lables))) for k,col in zip(unique_lables,colors):     x_k=X[labels==k]     plt.plot(x_k[:,0],x_k[:,1],'o',markerfacecolor=col,markeredgecolor="k",              markersize=14) # plt.title('data by make_blob()') # plt.show()  from pyspark import SparkContext  def closestPoint(p,centers):#计算某个元素的类别     bestIndex = 0#初始化类别     closest = float("+inf")#初始化某点与任意一聚类中心的最小距离为无穷大     for i in range(len(centers)):         tempDist = np.sum((p - centers[i]) ** 2)#某个元素到某个聚类中心的距离         if tempDist < closest:             closest = tempDist#更新与任意一聚类中心的最小距离             bestIndex = i#更新类别     return bestIndex sc=SparkContext() inputData=sc.parallelize(X).cache()#将原数据转换成rdd,每一个元素对应于一个样本点,并将数据缓存。这里每个元素是array([x1,x2])的形式。 K=3#初始化类的数目 convergeDist=0.01#初始化相临两次聚类中心的最小收敛距离,即如果新的聚类中心与上一次聚类中心距离很小了,就可以不用再继续优化了。 tempDist = 1#初始化相临两次聚类中心的距离 kPoints=inputData.takeSample(False,K,1)#随机抽取K个类中心,即初始化聚类中心。 #print(kPoints) #结果[array([ 1.04321307,  1.43628205]), array([ 0.85610326, -0.81389251]), array([-1.42721827, -1.14799597])] while tempDist > convergeDist:     closest = inputData.map(lambda p: (closestPoint(p, kPoints), (p, 1)))#将元素映射到这样的键值对,元素---->(类别,(元素,1))     #print(closest.collect())     #结果[(0, (array([ 1.68092639,  0.5636903 ]), 1)), ..., (2, (array([-1.36763066, -0.74669111]), 1))]     pointStats = closest.reduceByKey(lambda p1_c1, p2_c2: (p1_c1[0] + p2_c2[0], p1_c1[1] + p2_c2[1]))#(类别,(元素,1))---->(类别,(array(sum(维度1),sum(维度2)), n))     #print(pointStats.collect())     #结果[(0, (array([ 67.85854692,  71.4189192 ]), 67)), (1, (array([ 62.88505036, -68.0744321 ]), 67)), (2, (array([-69.06467775, -68.44964606]), 66))]     newPoints = pointStats.map(lambda st: (st[0], st[1][0] / st[1][1])).collect()#计算新的聚类中心     #print(newPoints)     #结果[(0, array([ 1.01281413,  1.06595402])), (1, array([ 0.93858284, -1.0160363 ])), (2, array([-1.04643451, -1.03711585]))]     tempDist = sum(np.sum((kPoints[iK] - p) ** 2) for (iK, p) in newPoints)#计算相临两次聚类中心的距离     #print(tempDist)     #结果0.343022614898     for (iK, p) in newPoints:#更新聚类中心         kPoints[iK] = p print("Final centers: " + str(kPoints)) newInput=closest.collect()  #这里先这样画 for p in newInput:     if p[0]==0:         plt.plot(p[1][0][0], p[1][0][1], '*', markerfacecolor='g', markeredgecolor='b',                  markersize=14)     elif p[0]==1:         plt.plot(p[1][0][0], p[1][0][1], '*', markerfacecolor='b', markeredgecolor='r',                  markersize=14)     else:         plt.plot(p[1][0][0], p[1][0][1], '*', markerfacecolor='r', markeredgecolor='g',                  markersize=14) plt.title('kmeansByPySpark') plt.show()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70



图中,圆圈是原始类别,五角星是通过聚类学习到的类别,可以看到聚类完全正确。

flatMap(f)

flatMap的用法与map类似,只不过map是一个输入元素对应一个输出元素,而flatMap一个输入元素对应多个输出元素。

from pyspark import SparkContext sc=SparkContext() x=sc.parallelize([1,2,3]) xFM1=x.flatMap(lambda x:(x,x*100,x**2)) xFM2=x.flatMap(lambda x:[x,x*100,x**2]) xFM3=x.flatMap(lambda x:(x,(x*100,x**2))) print(x.collect()) print(xFM1.collect()) print(xFM2.collect()) print(xFM3.collect()) #结果如下: #[1, 2, 3] #[1, 100, 1, 2, 200, 4, 3, 300, 9] #[1, 100, 1, 2, 200, 4, 3, 300, 9] #[1, (100, 1), 2, (200, 4), 3, (300, 9)] #所以不管是组合成一个元组,还是组合成一个列表,最后都会把里面的每一个单元当成是输出rdd的一个元素,这就是一对多;但是里面的单元只深入到第一层,不会继续拆分,否则就无法控制。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

mapValues(f)

将键值对形式的rdd的值用函数f来作用,而保持键不变,同时分区不变。

flatMapValues(f)[source]

综合flatMap和mapValues的特点。

mapPartitions(f, preservesPartitioning=False)

与map不同,map是对每一个元素用函数作用;而mapPartitions是对每一个分区用一个函数去作用,每一个分区的元素先构成一个迭代器iterator,iterator是一个像列表,但里面的元素又保持分布式特点的一类对象;输入的参数就是这个iterator,然后对iterator进行运算,iterator支持的函数不是太多,sum,count等一些spark定义的基本函数应该都是支持的。但如果要进行更为复杂的一些个性化函数运算,可以就用不了。实践中发生可以通过[x for i in iterator]的方式,将iterator转换为列表,然后就可以进行各种操作。但是这样在分区内部或分组内部就失去了分布式运算的特点。

x=sc.parallelize([1,2,3],2) def f(iterator):yield sum(iterator) xMP=x.mapPartitions(f) print(x.glom().collect()) print(xMP.glom().collect()) #结果为: #[[1], [2, 3]] #[[1], [5]]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

mapPartitionsWithIndex

与mapPartition相比,mapPartitionWithIndex能够保留分区索引,函数的传入参数也是分区索引和iterator构成的键值对。给了我们操作分区索引的机会,至于最后的结果要不要保留分区索引那是另一回事。

x=sc.parallelize([1,2,3],2) def f1(partitionIndex,iterator):yield (partitionIndex,sum(iterator)) def f2(partitionIndex,iterator):yield sum(iterator) xMP1=x.mapPartitionsWithIndex(f1) xMP2=x.mapPartitionsWithIndex(f2) print(x.glom().collect()) print(xMP1.glom().collect()) print(xMP2.glom().collect()) #结果为: #[[1], [2, 3]] #[[(0, 1)], [(1, 5)]] #[[1], [5]]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

partitionBy(numPartitions, partitionFunc=)

按给定的分区数和映射方法进行分区

pairs = sc.parallelize([1, 2, 3, 4, 2, 4, 1]).map(lambda x: (x, x)) print(pairs.collect()) sets = pairs.partitionBy(2).glom().collect() print(sets)
  • 1
  • 2
  • 3
  • 4

结果如下:

[(1, 1), (2, 2), (3, 3), (4, 4), (2, 2), (4, 4), (1, 1)] [[(4, 4), (2, 2), (4, 4), (2, 2)], [(1, 1), (3, 3), (1, 1)]]
  • 1
  • 2

rdd.coalesce(numPartitions,shuffle=none)

按时新的分区数重新分区

print(sc.parallelize([1,2,3,4,5,6],3).glom().collect()) print(sc.parallelize([1,2,3,4,5,6],3).coalesce(2).glom().collect())
  • 1
  • 2

结果如下:

[[1, 2], [3, 4], [5, 6]] [[1, 2], [3, 4, 5, 6]]
  • 1
  • 2

rdd.repartition(numPartitions)

按时新的分区数重新分区

rdd.zip(other)

将第一个rdd的元素作用键,第二个rdd的元素作为值,组成新rdd的元素。

x=sc.parallelize(['B','A','A']) y=x.map(lambda x:ord(x)) z=x.zip(y) print(x.collect()) #结果为:['B', 'A', 'A'] print(y.collect()) #结果为:[66, 65, 65] print(z.collect()) #结果为:[('B', 66), ('A', 65), ('A', 65)]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

rdd.zipWithIndex()

将rdd的元素作键,索引(可以理解为看到的位置索引)作为值,组成新rdd的元素。

x=sc.parallelize(['B','A','A'],2) y=x.zipWithIndex() print(x.collect()) print(y.collect()) #结果为:[['B'], ['A', 'A']] #结果为:[[('B', 0)], [('A', 1), ('A', 2)]]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

rdd.zipWithUniqueId()



Items in the kth partition will get ids k, n+k, 2*n+k, …, where n is the number of partitions. So there may exist gaps, but this method won’t trigger a spark job, which is different from zipWithIndex

rdd.keyBy(f)

为rdd中的每个元素按照函数f生成一个键,新rdd的元素以元组形式存在。

x=sc.parallelize([1,2,3]) y=x.keyBy(lambda x:x**2) print(x.collect()) #结果为[1, 2, 3] print(y.collect()) #结果为[(1, 1), (4, 2), (9, 3)]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

rdd.foreach(f)

对RDD中的每个元素使用函数来作用,由于是直接对每个元素操作并产生结果,所以得到的结果不是rdd,而是普通python对象。这与foreachPartition不同。

from pyspark import SparkContext sc=SparkContext() rdd_data=sc.parallelize([1,2,3,4,5],2) print(rdd_data.glom().collect()) def f(x):     print(x) list_new=rdd_data.foreach(f)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

结果如下:

[[1, 2], [3, 4, 5]] 3 4 5 1 2
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

一个将rdd元素逐个写到文件中的例子:

inputData=sc.parallelize([1,2,3]) def f(x):#定义一个将内容追加于文件末尾的函数     with open('./example.txt','a+') as fl:         print(x,file=fl)  open('./example.txt','w').close()#操作之前先关闭之前可能存在的对该文件的写操作 y=inputData.foreach(f) print(y) #结果为:None,因为函数f没有返回值 #查看写文件的结果 with open('./example.txt') as fl:     print(fl.read()) #结果为: ''' 1 2 3 ''' #说明每一个元素都被写到文件'./example.txt'中去了。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

rdd.foreachpartition

对RDD的每一个分区使用函数来作用

from pyspark import SparkContext sc=SparkContext() rdd_data=sc.parallelize([1,2,3,4,5],2) print(rdd_data.glom().collect()) def f(iterator):     for x in iterator:         print(x) list_new=rdd_data.foreachPartition(f)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

结果如下:

[[1, 2], [3, 4, 5]] 1 3 2 4 5
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

写分区内容的例子

inputData=sc.parallelize([1,2,3],5) print(inputData.glom().collect()) #结果为: #[[], [1], [], [2], [3]] def f(x):#定义一个将内容追加于文件末尾的函数     with open('./example.txt','a+') as fl:         print(list(x),file=fl)#先对分区序列进行转化再写入到文件中  open('./example.txt','w').close()#操作之前先关闭之前可能存在的对该文件的写操作 y=inputData.foreachPartition(f) print(y) #结果为:None,因为函数f没有返回值 #查看写文件的结果 with open('./example.txt') as fl:     print(fl.read()) #结果为: ''' [] [] [2] [1] [3] ''' #说明每一个分区序列都被写到文件'./example.txt'中去了。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

rdd.groupByKey(numPartitions=None, partitionFunc=)

原rdd为键值对,groupByKey()则将原rdd的元素相同键的值编进一个sequence(不知道与list和iterator的不同有多大,可以暂时当成iterator看)

rdd = sc.parallelize([("a", 1), ("b", 1), ("a", 1)]) rddGp=rdd.groupByKey() print(rdd.collect()) print(rddGp.collect()) #结果如下: #[('a', 1), ('b', 1), ('a', 1)] #[('a', <pyspark.resultiterable.ResultIterable object at 0x7fe1e3f88710>), ('b', <pyspark.resultiterable.ResultIterable object at 0x7fe1e3f88668>)] #从结果看,确实是将键相同的值编到一个序列里了,但类型很奇怪。这样看没有什么用处。但是后面可以接其他函数,一般都接mapValues(f),这样就可以完成按对值的一些操作。 def f(x):     a=list(x)#直接使用x会报错,说明sequence并不能用for     for i in range(len(a)):         a[i]=a[i]*2     return a  gpMp1=rddGp.mapValues(len) gpMp2=rddGp.mapValues(list) gpMp3=rddGp.mapValues(f) print(gpMp1.collect()) print(gpMp2.collect()) print(gpMp3.collect()) #结果如下: #[('a', 2), ('b', 1)],按键计算对应值的个数 #[('a', [1, 1]), ('b', [1])],按键将值转换成列表形式 #[('a', [2, 2]), ('b', [2])],通过自定义函数可以按键对值实现更复杂的操作。 #groupByKey()+mapValues()与reduceByKey()的过程很像,但两者运行效率相差很大,在能够用reduceByKey()或aggregateByKey的时候,尽量不要用groupByKey()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

groupByKey()和flatPapValues()综合应用

rdd.groupBy(f, numPartitions=None, partitionFunc=)

groupBy()的用法与groupByKey相似,但传入参数多了f,传入的函数f可以把它当成用来生成新的key的。它也围绕这个潜在的key将值编进一个序列。可以看得出来,它比groupByKey更灵活。

rdd = sc.parallelize([1, 1, 2, 3, 5, 8]) result=rdd.groupBy(lambda x:x%2)#按余数来分组 #后面紧接着一般是mapValues函数做进一步处理,这里我们直接获取该数据而不做进一步处理。 print(result.collect()) #结果如下 [(0, <pyspark.resultiterable.ResultIterable object at 0x7f336e26f550>), (1, <pyspark.resultiterable.ResultIterable object at 0x7f336e26f6a0>)] #所以要用for函数或在mapValues内部用list将pyspark.resultiterable.ResultIterable object转换出来 resultGp=[(x,sorted(y)) for (x,y) in result.collect()] print(resultGp) #结果如下: [(0, [2, 8]), (1, [1, 1, 3, 5])]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

rdd.reduce(f)

reduce函数是将rdd中的每个元素两两之间按函数f进行操作,然后再结果再两两之间按f进行操作,一直进行下去,即所谓的shuffle过程。reduce得到的结果是普通的python对象,而不是rdd.

rdd.keys()

原rdd的元素为键值对,返回原rdd元素的键为元素的rdd

rdd.values()

原rdd的元素为键值对,返回原rdd元素的值为元素的rdd

rdd.reduceByKey(func, numPartitions=None, partitionFunc=)

reduceByKey函数与reduce相似,但它是按key分组,在组内,将元素两两之间按函数f操作。可以看成是将value参数传入了,但最终结果又不丢失key的信息。更详细的使用,可参考上面介绍map函数时的例子。reduceByKey得到的结果是普通的python对象,而不是rdd.

rdd.reduceByKeyLocally(f)

其他与reduceByKey一样,只不过聚合后立即将键,值对以字典的形式传给到集群master

from operator import add inputRdd=sc.parallelize([("a", 1), ("b", 1), ("a", 1)]) rddRBKL=inputRdd.reduceByKeyLocally(add) print(inputRdd.collect()) #结果为:[('a', 1), ('b', 1), ('a', 1)] print(rddRBKL) #结果为:{'a': 2, 'b': 1}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

fold(zeroValue, op)[source]

与partitionBy很像,只不过有一个起始值。fold函数是按分区对每个元素进行操作,即先每个元素与起始值按op进行操作,得到的结果再两两之间按op操作,一直进行下去得到分区结果,然后再将分区结果按op操作。

>>> from operator import add >>> x=sc.parallelize([1,2,3],2) >>> y=x.fold(1,lambda valueInitial,accumulated:accumulated+valueInitial)#这里的valueInitial,accumulated可以随便取名字,只表示输入 print(x.collect()) #结果为:[1, 2, 3] >>> print(y) #结果为9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

关于python内置操作op有哪些,可以使用help(‘operator’)进行查询,operator是一个专门的模块。这个模块是mapValues(f),reduce(),aggregate()等相似功能函数都能使用的。详细列举如下:

Help on module operator:  NAME     operator - Operator interface.  DESCRIPTION     This module exports a set of functions implemented in C corresponding     to the intrinsic operators of Python.  For example, operator.add(x, y)     is equivalent to the expression x+y.  The function names are those     used for special methods; variants without leading and trailing     '__' are also provided for convenience.  CLASSES     builtins.object         attrgetter         itemgetter         methodcaller      class attrgetter(builtins.object)      |  attrgetter(attr, ...) --> attrgetter object      |        |  Return a callable object that fetches the given attribute(s) from its operand.      |  After f = attrgetter('name'), the call f(r) returns r.name.      |  After g = attrgetter('name', 'date'), the call g(r) returns (r.name, r.date).      |  After h = attrgetter('name.first', 'name.last'), the call h(r) returns      |  (r.name.first, r.name.last).      |        |  Methods defined here:      |        |  __call__(self, /, *args, **kwargs)      |      Call self as a function.      |        |  __getattribute__(self, name, /)      |      Return getattr(self, name).      |        |  __new__(*args, **kwargs) from builtins.type      |      Create and return a new object.  See help(type) for accurate signature.      |        |  __reduce__(...)      |      Return state information for pickling      |        |  __repr__(self, /)      |      Return repr(self).      class itemgetter(builtins.object)      |  itemgetter(item, ...) --> itemgetter object      |        |  Return a callable object that fetches the given item(s) from its operand.      |  After f = itemgetter(2), the call f(r) returns r[2].      |  After g = itemgetter(2, 5, 3), the call g(r) returns (r[2], r[5], r[3])      |        |  Methods defined here:      |        |  __call__(self, /, *args, **kwargs)      |      Call self as a function.      |        |  __getattribute__(self, name, /)      |      Return getattr(self, name).      |        |  __new__(*args, **kwargs) from builtins.type      |      Create and return a new object.  See help(type) for accurate signature.      |        |  __reduce__(...)      |      Return state information for pickling      |        |  __repr__(self, /)      |      Return repr(self).      class methodcaller(builtins.object)      |  methodcaller(name, ...) --> methodcaller object      |        |  Return a callable object that calls the given method on its operand.      |  After f = methodcaller('name'), the call f(r) returns r.name().      |  After g = methodcaller('name', 'date', foo=1), the call g(r) returns      |  r.name('date', foo=1).      |        |  Methods defined here:      |        |  __call__(self, /, *args, **kwargs)      |      Call self as a function.      |        |  __getattribute__(self, name, /)      |      Return getattr(self, name).      |        |  __new__(*args, **kwargs) from builtins.type      |      Create and return a new object.  See help(type) for accurate signature.      |        |  __reduce__(...)      |      Return state information for pickling      |        |  __repr__(self, /)      |      Return repr(self).  FUNCTIONS     __abs__ = abs(...)         abs(a) -- Same as abs(a).      __add__ = add(...)         add(a, b) -- Same as a + b.      __and__ = and_(...)         and_(a, b) -- Same as a & b.      __concat__ = concat(...)         concat(a, b) -- Same as a + b, for a and b sequences.      __contains__ = contains(...)         contains(a, b) -- Same as b in a (note reversed operands).      __delitem__ = delitem(...)         delitem(a, b) -- Same as del a[b].      __eq__ = eq(...)         eq(a, b) -- Same as a==b.      __floordiv__ = floordiv(...)         floordiv(a, b) -- Same as a // b.      __ge__ = ge(...)         ge(a, b) -- Same as a>=b.      __getitem__ = getitem(...)         getitem(a, b) -- Same as a[b].      __gt__ = gt(...)         gt(a, b) -- Same as a>b.      __iadd__ = iadd(...)         a = iadd(a, b) -- Same as a += b.      __iand__ = iand(...)         a = iand(a, b) -- Same as a &= b.      __iconcat__ = iconcat(...)         a = iconcat(a, b) -- Same as a += b, for a and b sequences.      __ifloordiv__ = ifloordiv(...)         a = ifloordiv(a, b) -- Same as a //= b.      __ilshift__ = ilshift(...)         a = ilshift(a, b) -- Same as a <<= b.      __imatmul__ = imatmul(...)         a = imatmul(a, b) -- Same as a @= b.      __imod__ = imod(...)         a = imod(a, b) -- Same as a %= b.      __imul__ = imul(...)         a = imul(a, b) -- Same as a *= b.      __index__ = index(...)         index(a) -- Same as a.__index__()      __inv__ = inv(...)         inv(a) -- Same as ~a.      __invert__ = invert(...)         invert(a) -- Same as ~a.      __ior__ = ior(...)         a = ior(a, b) -- Same as a |= b.      __ipow__ = ipow(...)         a = ipow(a, b) -- Same as a **= b.      __irshift__ = irshift(...)         a = irshift(a, b) -- Same as a >>= b.      __isub__ = isub(...)         a = isub(a, b) -- Same as a -= b.      __itruediv__ = itruediv(...)         a = itruediv(a, b) -- Same as a /= b      __ixor__ = ixor(...)         a = ixor(a, b) -- Same as a ^= b.      __le__ = le(...)         le(a, b) -- Same as a<=b.      __lshift__ = lshift(...)         lshift(a, b) -- Same as a << b.      __lt__ = lt(...)         lt(a, b) -- Same as a<b.      __matmul__ = matmul(...)         matmul(a, b) -- Same as a @ b.      __mod__ = mod(...)         mod(a, b) -- Same as a % b.      __mul__ = mul(...)         mul(a, b) -- Same as a * b.      __ne__ = ne(...)         ne(a, b) -- Same as a!=b.      __neg__ = neg(...)         neg(a) -- Same as -a.      __not__ = not_(...)         not_(a) -- Same as not a.      __or__ = or_(...)         or_(a, b) -- Same as a | b.      __pos__ = pos(...)         pos(a) -- Same as +a.      __pow__ = pow(...)         pow(a, b) -- Same as a ** b.      __rshift__ = rshift(...)         rshift(a, b) -- Same as a >> b.      __setitem__ = setitem(...)         setitem(a, b, c) -- Same as a[b] = c.      __sub__ = sub(...)         sub(a, b) -- Same as a - b.      __truediv__ = truediv(...)         truediv(a, b) -- Same as a / b.      __xor__ = xor(...)         xor(a, b) -- Same as a ^ b.      abs(...)         abs(a) -- Same as abs(a).      add(...)         add(a, b) -- Same as a + b.      and_(...)         and_(a, b) -- Same as a & b.      concat(...)         concat(a, b) -- Same as a + b, for a and b sequences.      contains(...)         contains(a, b) -- Same as b in a (note reversed operands).      countOf(...)         countOf(a, b) -- Return the number of times b occurs in a.      delitem(...)         delitem(a, b) -- Same as del a[b].      eq(...)         eq(a, b) -- Same as a==b.      floordiv(...)         floordiv(a, b) -- Same as a // b.      ge(...)         ge(a, b) -- Same as a>=b.      getitem(...)         getitem(a, b) -- Same as a[b].      gt(...)         gt(a, b) -- Same as a>b.      iadd(...)         a = iadd(a, b) -- Same as a += b.      iand(...)         a = iand(a, b) -- Same as a &= b.      iconcat(...)         a = iconcat(a, b) -- Same as a += b, for a and b sequences.      ifloordiv(...)         a = ifloordiv(a, b) -- Same as a //= b.      ilshift(...)         a = ilshift(a, b) -- Same as a <<= b.      imatmul(...)         a = imatmul(a, b) -- Same as a @= b.      imod(...)         a = imod(a, b) -- Same as a %= b.      imul(...)         a = imul(a, b) -- Same as a *= b.      index(...)         index(a) -- Same as a.__index__()      indexOf(...)         indexOf(a, b) -- Return the first index of b in a.      inv(...)         inv(a) -- Same as ~a.      invert(...)         invert(a) -- Same as ~a.      ior(...)         a = ior(a, b) -- Same as a |= b.      ipow(...)         a = ipow(a, b) -- Same as a **= b.      irshift(...)         a = irshift(a, b) -- Same as a >>= b.      is_(...)         is_(a, b) -- Same as a is b.      is_not(...)         is_not(a, b) -- Same as a is not b.      isub(...)         a = isub(a, b) -- Same as a -= b.      itruediv(...)         a = itruediv(a, b) -- Same as a /= b      ixor(...)         a = ixor(a, b) -- Same as a ^= b.      le(...)         le(a, b) -- Same as a<=b.      length_hint(...)         length_hint(obj, default=0) -> int         Return an estimate of the number of items in obj.         This is useful for presizing containers when building from an         iterable.          If the object supports len(), the result will be         exact. Otherwise, it may over- or under-estimate by an         arbitrary amount. The result will be an integer >= 0.      lshift(...)         lshift(a, b) -- Same as a << b.      lt(...)         lt(a, b) -- Same as a<b.      matmul(...)         matmul(a, b) -- Same as a @ b.      mod(...)         mod(a, b) -- Same as a % b.      mul(...)         mul(a, b) -- Same as a * b.      ne(...)         ne(a, b) -- Same as a!=b.      neg(...)         neg(a) -- Same as -a.      not_(...)         not_(a) -- Same as not a.      or_(...)         or_(a, b) -- Same as a | b.      pos(...)         pos(a) -- Same as +a.      pow(...)         pow(a, b) -- Same as a ** b.      rshift(...)         rshift(a, b) -- Same as a >> b.      setitem(...)         setitem(a, b, c) -- Same as a[b] = c.      sub(...)         sub(a, b) -- Same as a - b.      truediv(...)         truediv(a, b) -- Same as a / b.      truth(...)         truth(a) -- Return True if a is true, False otherwise.      xor(...)         xor(a, b) -- Same as a ^ b.  DATA     __all__ = ['abs', 'add', 'and_', 'attrgetter', 'concat', 'contains', '...  FILE     c:\users\csw\miniconda2\envs\guanwang\lib\operator.py
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394

foldByKey(zeroValue, func, numPartitions=None, partitionFunc=)[source]

foldByKey的操作与fold几乎一样,只不过前者按键来分组,后者按分区分组,前者不同键不再进一步操作,后者不同分区结果还会进一步操作。foldByKey最终结果也是普通python对象,而不是rdd。一个键占一个元组的空间,存放在list中。

>>> from operator import add >>> rdd = sc.parallelize([("a", 1), ("b", 1), ("a", 1)]) >>> rddFB=sorted(rdd.foldByKey(1, add).collect()) >>> print(rdd.collect()) #结果为:[('a', 1), ('b', 1), ('a', 1)] >>> print(rddFB) #结果为:[('a', 4), ('b', 2)]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

RDD.aggregate(zeroValue, seqOp, combOp)


seqOp操作会聚合各分区中的元素,然后combOp操作把所有分区的聚合结果再次聚合,两个操作的初始值都是zeroValue. seqOp的操作是遍历分区中的所有元素(T),zeroValue跟第一个T做操作,结果再作为与第二个T做操作的zeroValue,直到遍历完整个分区。combOp操作是把各分区聚合的结果,再聚合,zeroValue与第一个分区结果聚合,聚合结果相当于新的zeroValue,再与第二个分区结果聚合,一直进行下去。aggregate函数返回一个跟RDD不同类型的值。因此,需要一个操作seqOp来把分区中的元素T合并成一个U,另外一个操作combOp把所有U聚合。

seqOp=(lambda x,y:(x[0]+y,x[1]+1)) combOp=(lambda x,y:(x[0]+y[0],x[1]+y[1])) x=sc.parallelize([1,2,3,4,5,6],2) print(x.glom().collect()) #结果为:[[1, 2, 3], [4, 5, 6]] y=x.aggregate((1,2),seqOp,combOp) print(y) #结果为:(24, 12)  #计算过程如下: #(1,2)--》(1+1,2+1)-->(2+2,3+1)-->(4+3,4+1)-->(7,5); #(1,2)--》(1+4,2+1)-->(5+5,3+1)-->(10+6,4+1)-->(16,5); #(1,2)--》(1+7,2+5)-->(8+16,7+5)-->(24,12);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

RDD.aggregateByKey(zeroValue, seqFunc, combFunc, numPartitions=None, partitionFunc=)

aggregate是按分区进行,而aggregateByKey是按键来进行,但是zeroValue与aggregate中的用法很不一样,这里的zeroValue是一个值,它即可以跟这样键聚合,也可以跟那个键聚合,而且zeroValue必须与键内聚合时定义的形式一致。

x=sc.parallelize([('B', 1), ('B', 2), ('B', 3), ('A', 4), ('A', 5),('A', 6)]) zeroValue=[7] mergeVal=(lambda aggregated,el:aggregated+[(el,el**2)]) mergeComb=(lambda agg1,agg2:agg1+agg2) y=x.aggregateByKey(zeroValue,mergeVal,mergeComb) print(x.collect()) #结果为:[('B', 1), ('B', 2), ('B', 3), ('A', 4), ('A', 5), ('A', 6)] print(y.collect()) #结果为:[('A', [7, (4, 16), (5, 25), (6, 36)]), ('B', [7, (1, 1), (2, 4), (3, 9)])] #计算过程如下: #('B', [7]);('B', (1,1**2))-->('B', [7,(1,1)])-->('B', [7,(1,1)]);('B', (2,2**2))-->('B', [7,(1,1),(2,4)])...-->[('B', [7, (1, 1), (2, 4), (3, 9)])] 同时'A'也进行这样的过程 #[('B', [7, (1, 1), (2, 4), (3, 9)])];[('A', [7, (4, 16), (5, 25), (6, 36)])]-->[('A', [7, (4, 16), (5, 25), (6, 36)]), ('B', [7, (1, 1), (2, 4), (3, 9)])]
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

combineByKey(createCombiner, mergeValue, mergeCombiners, numPartitions=None, partitionFunc=)




mergeCombiners: (C, C) => C,该函数把2个元素C合并 (这个操作在不同键间进行),在不同键之间进行合并

sc=SparkContext() x=sc.parallelize([('a',1),('a',2),('b',1),('b',3),('c',5),('c',6)]) def to_list(a):     return [a] def append(a,b):     a.append(b)     return a def extend(a,b):     a.extend(b)     return a print(x.collect()) print(x.combineByKey(to_list,append,extend).collect())
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

结果如下:

[('a', 1), ('a', 2), ('b', 1), ('b', 3), ('c', 5), ('c', 6)] [('c', [5, 6]), ('b', [3, 1]), ('a', [1, 2])] #计算过程如下: #('a', 1)-->('a', [1]);...;('c', 6)-->('c', [6]) #('a', [1]);('a', [2])-->('a', [1,2]);...;-->('c', [5]);('c', [6])-->('c', [5,6]) #('a', [1,2]);('b', [3, 1]);('c', [5,6])-->[('a', [1,2]),('b', [3, 1]),('c', [5,6])];当然这一结果并没有立即计算出来,而是定义了这种操作方法。
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

rdd.sortByKey()

首先rdd的元素需要为键值对,然后sortByKey()就能实现对每个元素按键的大小来排序

x=sc.parallelize([('B',1),('A',2),('C',3)]) y=x.sortByKey() print(x.collect()) print(y.collect()) #结果为 #[('B', 1), ('A', 2), ('C', 3)] #[('A', 2), ('B', 1), ('C', 3)] #从结果可以看到默认是升序排列
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

rdd.sortBy()

        
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!