基於Python+Spark分佈式數據操作:求精確中位數並驗證
Problem Restatement:
- 生成1萬個隨機數,存儲在HDFS文件系統中的data1.txt中,每個數字之間用“,”分隔。在Spark平臺上實現如下的功能:
- 從HDFS上讀入data1.txt,生成RDD;
- 找到這個數據集合的中位數(精確的);
- 只能使用RDD有關API,並且不能調用Spark提供的中位數計算的API;
- 在Spark平臺上實現中位數算法後,驗證結果的正確性。
Data Generating
generator.py
- 根據要求生成數據:限定數據量
N = 10000
,數據範圍爲M = 100
,即-50~+50
- 打開輸出文件
filename = ".\data1.txt"
with open(filename, "w", encoding="utf-8") as file:
...
- 導入
random
庫,使用random.random()
生成0~1
的數據,轉換爲指定範圍 - 用’,‘分隔,並保留6位小數’
for i in range(N):
if i != 0:
file.write(",")
file.write(str(round((random.random() - 0.5) * M, 6)))
Preliminary
work.ipynb
- 生成
sc
和spark
對象
from pyspark import SparkConf, SparkContext
from pyspark.sql import SparkSession
from pyspark.sql.functions import col
sc = SparkContext(conf=SparkConf())
spark = SparkSession.builder.master("local[*]").appName("FirstApp").getOrCreate()
Calculate
work.ipynb
-
總體思路:通過設置鍵值對和利用
RDD.sortByKey()
方法對數據排序,取中位數 -
打開文件,導入數據,利用
str.split()
分隔字符串
file = open("hdfs://master:9000/sparkdata/data1.txt")
dataStrList = file.read().split(',')
- 將字符串轉換爲浮點類型
dataFloatList = []
for i in dataStrList:
dataFloatList.append(float(i))
- 創建
RDD
,生成鍵值對 - 排序
- 取出
Mapped RDD
鍵集合
data = sc.parallelize(dataFloatList)
dataMapped = data.map(lambda x: (x, x))
dataSorted = dataMapped.sortByKey(lambda x: x[0]).keys()
- 統計元素數
- 區分奇偶情況(可省略)
- 計算中位數
N = dataSorted.count()
if N % 2 == 0:
preHalfList = dataSorted.take(N / 2 + 1)
avg = (preHalfList[-1] + preHalfList[-2]) / 2
else:
avg = dataSorted.take(N / 2 + 1)[-1]
- 得出結果
>>> avg
>>> -0.435513
Verification
work.ipynb
-
總體思路:通過計算比得出的
avg
更大數字的個數cntM
和更小得數字的個數cntN
是否相等,判斷是否爲中位數 -
初始化
cntM = 0
cntN = 0
- 通過
RDD.collect()
將RDD
轉換爲list
dataSortedList = dataSorted.collect()
- 統計比
avg
更大數字的個數cntM
和更小得數字的個數cntN
for i in dataSortedList:
if (i >= avg):
cntM += 1
else:
cntN +=1
- 輸出結果驗證
>>> cntM, cntN, cntM == cntN
>>> (5000, 5000, True)
Conclusion
- 首先隨機生成10000個浮點數,存儲到
data1.txt
中; - 然後基於
pyspark
環境導入文件、分隔字符串並轉換爲浮點類型、構建RDD
對象; - 再生成
Map
鍵值對,進行排序,取出中間兩個數字做平均值,作爲中位數; - 最後統計原數組中比該“中位數”大/小的數字的個數,相等則驗證該“求中位數算法”正確。