簡體   English   中英

使用Apache-Spark分析時間序列

[英]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

快速檢查:

  • [0.01,1.01]:3
  • [1.01,2.01]:4
  • [2.01,3.01]:0
  • [3.01,4.01]:1
  • [4.01,5.01]:1

它給出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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM