[英]Using Apache-Spark to analyze time series
我有非常大的時間序列數據,數據格式是:(arrival_time,key,value),時間單位是秒,例如:
0.01, k, v
0.03, k, v
....
1.00, k, v
1.10, k, v
1.20, k, v
1.99, k, v
2.00, k, v
...
我需要做的是獲得整個數據的每秒行數。 到現在為止,我使用pySpark,我的代碼如下:
linePerSec = []
lo = rdd.take(1)[0]
hi = lo + 1.0
end = rdd.collect()[-1][0]
while(hi < end):
number = rdd.filter(lambda (t, k, v): t >= lo and t < hi).count()
linePerSec.append(number)
lo = hi
hi = lo + 1.0
但它非常慢,甚至比在for循環中逐行遍歷數據更慢。 我想這是因為rdd.filter()遍歷整個rdd以找到滿足過濾條件的行。 但是對於時間序列,我們不需要在代碼中的hi邊界之后遍歷數據。 在我的情況下,是否有任何解決方案讓火花停止通過rdd? 謝謝!
首先讓我們創建一些虛擬數據:
rdd = sc.parallelize(
[(0.01, "k", "v"),
(0.03, "k", "v"),
(1.00, "k", "v"),
(1.10, "k", "v"),
(1.20, "k", "v"),
(1.99, "k", "v"),
(2.00, "k", "v"),
(3.10, "k", "v"),
(4.50, "k", "v")])
從RDD中提取時間字段:
def get_time(x):
(start, _, _) = x
return start
times = rdd.map(get_time)
接下來,我們需要一個從時間到鍵的函數映射:
def get_key_(start):
offset = start - int(start)
def get_key(x):
w = int(x) + offset
return w if x >= w else int(x - 1) + offset
return get_key
找到最短和最長時間
start = times.takeOrdered(1)[0]
end = times.top(1)[0]
生成一個實際的鍵功能:
get_key = get_key_(start)
並計算平均值
from operator import add
total = (times
.map(lambda x: (get_key(x), 1))
.reduceByKey(add)
.values()
.sum())
time_range = get_key(end) - get_key(start) + 1.0
mean = total / time_range
mean
## 1.8
快速檢查:
它給出9/5 = 1.8
等效的數據框可以如下所示:
from pyspark.sql.functions import count, col, sum, lit, min, max
# Select only arrival times
arrivals = df.select("arrival_time")
# This is almost identical as before
start = df.agg(min("arrival_time")).first()[0]
end = df.agg(max("arrival_time")).first()[0]
get_key = get_key_(start)
time_range = get_key(end) - get_key(start) + 1.0
# But we'll need offset as well
offset = start - int(start)
# and define a bucket column
bucket = (col("arrival_time") - offset).cast("integer") + offset
line_per_sec = (df
.groupBy(bucket)
.agg(count("*").alias("cnt"))
.agg((sum("cnt") / lit(time_range)).alias("mean")))
line_per_sec.show()
## +----+
## |mean|
## +----+
## | 1.8|
## +----+
請注意,這與Nhor提供的解決方案非常相似,主要有兩點不同:
我要做的是第一次將時間值置於最低點:
from pyspark.sql.functions import *
df = df.select(floor(col('arrival_time')).alias('arrival_time'))
現在你有你的arrival_time
地板,你准備好來計算每種第二行數:
df = df.groupBy(col('arrival_time')).count()
現在,當您計算每秒的行數時,您可以獲取所有行並按計數除以它們以獲得每秒的平均行數:
lines_sum = df.select(sum(col('count')).alias('lines_sum')).first().lines_sum
seconds_sum = df.select(count(col('arrival_time')).alias('seconds_sum')).first().seconds_sum
result = lines_sum / seconds_sum
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.