我正在嘗試為例外檢測生成一個隨機資料序列(或時間序列),事件跨越幾個連續的資料點。它們可能是高于/低于某個閾值的值,或者是具有不同已知概率的例外型別。
例如,在 1 為正常且事件型別在 [2, 3, 4] 范圍內的情況下:
11112221113333111111112211111
我查看了np.randomandrandom方法,但找不到任何生成這些事件的方法。我當前的解決方案是選擇隨機點,向它們添加隨機持續時間以生成事件開始和結束位置,用隨機事件型別標記每個事件,然后加入資料集,例如:
import numpy as np
num_events = np.random.randint(1, 10)
number_series = [1]*60
first_pos = 0
event_starts = sorted([first_pos i for i in np.random.randint(50, size = num_events)])
event_ends = [sum(i) for i in list(zip(event_starts, np.random.randint(8, size = num_events)))]
for c in list(zip(event_starts, event_ends)):
rand_event_type = np.random.choice(a = [2, 3, 4], p = [0.5, 0.3, 0.2])
number_series[c[0]:c[1]] = [rand_event_type]*len(number_series[c[0]:c[1]])
print(number_series)
[1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 3, 3, 4, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
但我想知道是否有一種更簡單的方法可以根據一組概率生成一系列帶有事件的數字。
uj5u.com熱心網友回復:
這完全取決于您如何為流程建模(您要模擬的底層流程)。您可以在 Wikipedia 上閱讀更多關于一些常用模型的資訊。
最簡單的
在下文中,我們使用一個非常簡單的模型(與您的模型略有不同):每個事件都有一個概率(如您的問題)和一個獨立于事件本身的隨機持續時間。1("normal") 是與其他任何事件一樣的事件(與您的示例代碼不同)。我們可以改變它,但現在這是你能想到的最簡單的模型之一。
def gen_events(n):
events = np.random.choice(a=[1, 2, 3, 4], p=[0.6, 0.2, 0.12, 0.08], size=n)
durations = np.random.randint(1, 8, size=n)
return np.repeat(events, durations)
np.random.seed(0) # repeatable example
number_series = gen_events(10) # for example
>>> number_series
array([1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1,
1, 2, 2, 1, 1, 1, 1, 1, 1, 3, 4, 4, 1, 1, 1, 1, 1])
請注意,這非常快:
%timeit gen_events(1_000_000)
# 44.9 ms ± 138 μs per loop (mean ± std. dev. of 7 runs, 10 loops each)
馬爾可夫鏈
另一個模型(更容易引數化,實作起來更復雜)是馬爾可夫模型。其中最簡單的是馬爾可夫鏈。這是一個超級簡單(但不是很有效)的版本:
def markov_chain(P, n, initial_state=0):
m = P.shape[0]
ix = np.arange(m)
s = np.empty(n, dtype=int)
s[0] = initial_state
for i in range(1, n):
s[i] = np.random.choice(ix, p=P[s[i-1]])
return s
上面P是一個轉移矩陣,其中每個單元格是從一個狀態轉移到另一個P[i,j]狀態的概率。這是一個示例應用程式:ij
P = np.array([
[.7, .1, .12, .08], # from 0 to others
[.3, .6, .05, .05],
[.3, 0, .65, .05],
[.4, 0, .05, .55],
])
np.random.seed(0)
n = 100
s = markov_chain(P, n) 1
>>> s
array([1, 1, 2, 2, 2, 2, 2, 2, 2, 4, 1, 2, 2, 2, 3, 1, 1, 1, 3, 3, 3, 4,
4, 4, 4, 1, 1, 1, 4, 4, 3, 1, 2, 2, 2, 1, 1, 1, 1, 4, 4, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 3, 1, 3, 1, 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 4, 1, 1, 1, 2, 1, 1, 1, 1, 3])
請注意,每個事件的一元概率被呼叫pi并對應于 的任何行lim_{k -> \infty} P**k:
>>> pd.Series(markov_chain(P, 1000, 0)).value_counts(normalize=True).sort_index()
0 0.530
1 0.135
2 0.209
3 0.126
>>> np.linalg.matrix_power(P, 40)[0]
array([0.52188552, 0.13047138, 0.21632997, 0.13131313])
uj5u.com熱心網友回復:
一種不那么冗長的方法是在旅途中生成您的事件串列。
例如,設定例外發生的概率(例如 5%)。然后,
events = []
for i in range(60):
if random() <= 0.95:
events.append(1)
else:
events.extend([choice(a = [2, 3, 4], p = [0.5, 0.3, 0.2])] * randint(8))
uj5u.com熱心網友回復:
您可以從 [0, 1) 上的均勻分布生成亂數,并使用numpy.select并選擇1, 2, 3, 4如下所示的數字:
def generate_random_data_series(num, prob=[0.6,0.2,0.05,0.15]):
x = np.random.rand(num)
prob = np.asarray(prob)
condlist = [
x<np.sum(prob[:1]),
x<np.sum(prob[:2]),
x<np.sum(prob[:3]),
x<np.sum(prob)
]
choicelist = [1,2,3,4]
return np.select(condlist, choicelist, default=1)
colab的基準測驗:
%timeit generate_random_data_series(1_000_000)
# 25.1 ms per loop (10 loops, best of 5)
測驗功能:
>>> from collections import Counter
>>> res = generate_random_data_series(100)
>>> res
array([1, 1, 4, 1, 4, 1, 1, 1, 4, 1, 3, 4, 4, 1, 1, 1, 1, 4, 1, 1, 2, 1,
4, 1, 1, 1, 1, 1, 2, 1, 1, 4, 2, 1, 2, 1, 1, 1, 2, 2, 1, 1, 1, 2,
1, 2, 2, 1, 1, 4, 1, 1, 1, 2, 1, 3, 1, 1, 1, 1, 2, 1, 2, 1, 4, 1,
1, 1, 2, 1, 1, 1, 1, 4, 1, 4, 2, 4, 4, 4, 2, 3, 2, 2, 2, 2, 1, 1,
2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1])
>>> Counter(res)
Counter({1: 61, 4: 15, 3: 3, 2: 21})
# prob 1 : 60%
# count 1 : 61 in 100 random number
# prob 2 : 20%
# count 2 : 21 in 100 random number
# prob 3 : 5%
# count 3 : 3 in 100 random number
# prob 4 : 15%
# count 4 : 15 in 100 random number
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/485700.html
