2016-11-16 20 views
0

我正在尋找一種算法,可以從合理抽樣p的用戶百分比的無限列表。如何在用戶事件流中隨機抽樣p%的用戶

一個天真的算法看起來是這樣的:

//This is naive.. what is a better way?? 
def userIdToRandomNumber(userId: Int): Float = userId.toString.hashCode % 1000)/1000.0 

//An event listener will call this every time a new event is received 
def sampleEventByUserId(event: Event) = { 
    //Process all events for 3% percent of users 
    if (userIdToRandomNumber(event.user.userId) <= 0.03) { 
     processEvent(event) 
    } 
} 

沒有與此代碼的問題,但(的hashCode可能有利於較短的字符串,模運算的離散所以它不是完全的p值等)。

找到userId s的確定性映射到上面的函數userIdToRandomNumber的隨機數的「更正確」方法是什麼?

回答

1

嘗試下面的方法而不是hashCode。即使是短字符串,字符爲整數的值確保總和越過100。此外,避免分裂,使你避免舍入誤差

def inScope(s: String, p: Double) = modN(s, 100) < p * 100 

    def modN(s: String, n: Int): Int = { 
    var sum = 0 
    for (c <- s) { sum += c } 
    sum % n 
    } 
+0

不錯,但'modN()'只能返回's.sum%n'。 – jwvh

+0

@jwvh好趕上! – radumanolescu

0

這是一個非常簡單的映射,假設你的數據集是足夠大:

這是對大數據集一個實際使用的方法,併爲您提供完全隨機的結果!

我希望你可以很容易地在Scala中編寫代碼。


編輯:在評論,你提到確定性。我解釋說,如果你再次採樣,它會給你相同的結果。爲此,只需爲每個用戶存儲x。

此外,這將適用於任何數量的用戶(甚至無限)。您只需爲每個用戶生成一次x。映射只是userId -> x

EDIT2:在你的問題中的算法是有偏見的。假設有p = 10%,並且有1100個用戶(userIds 1-1100)。第一個1000用戶有一個10%被選中的機會,下一個100有一個100%的機會。此外,哈希將用戶ID映射到新的值,但仍然沒有保證模1000會給你一個統一的樣本!

+0

感謝您的快速回復,但我的問題是特別如何映射'用戶id - > [0,1]'中一個完全隨機的方式(儘管,同一個用戶應該總是映射到相同的值)。我不知道用戶ID是什麼,所以我需要確定性的方法來做這個映射。 – anthonybell

+0

@anthonybell你說隨機抽樣?通過確定性,如果你重新運行,你的意思是相同的樣本嗎? – prakharsingh95

+0

用戶數量可能是無限的,因爲它是層出不窮的用戶。 – anthonybell

0

我想出了一個解決方案的確定性隨機樣本用戶從完全是隨機的一個流(假設隨機數發生器是完全隨機的):

def sample(x: AnyRef, percent: Double): Boolean = { 
    new Random(seed=x.hashCode).nextFloat() <= percent 
} 

//sample 3 percent of users 
if (sample(event.user.userId, 0.03)) { 
    processEvent(event) 
}