2012-07-25 30 views
22

Tôi đã đọc + nghiên cứu về thuật toán và công thức để tìm ra điểm số cho nội dung do người dùng gửi của mình để hiển thị các mặt hàng đang nóng/thịnh hành cao hơn danh sách, tuy nhiên tôi sẽ thừa nhận tôi ' m một chút trên đầu tôi ở đây.Thuật toán/điểm số nội dung nóng với thời gian phân rã

tôi sẽ cung cấp một số nền tảng trên những gì tôi sau khi ... người dùng tải lên âm thanh đến trang web của tôi, âm thanh có một vài hành động:

  • Chơi
  • Downloaded
  • Thích
  • Được yêu thích nhất

Lý tưởng nhất tôi muốn một thuật toán nơi tôi có thể cập nhật điểm số âm thanh mỗi khi một hoạt động mới được ghi lại (phát, tải xuống v.v ...), cũng là một hành động tải xuống có giá trị hơn một trò chơi, giống như một lượt tải xuống và một lượt yêu thích nhiều hơn một lượt thích.

Nếu có thể, tôi muốn âm thanh cũ hơn 1 tuần sẽ giảm khá mạnh khỏi danh sách để cung cấp nội dung mới hơn nhiều khả năng xu hướng.

Tôi đã đọc về thuật toán reddits có vẻ tốt, nhưng tôi đang ở trên đầu của tôi về cách tinh chỉnh nó để sử dụng nhiều biến của tôi và thả các bài viết cũ sau khoảng 7 ngày.

Một số bài báo mà chúng tôi thú vị:

Any help is appreciated!

Paul

+0

Vậy câu hỏi là gì? –

+0

Nội dung nóng với thời gian phân rã? Bạn đang nói về [phương trình nhiệt] (http://en.wikipedia.org/wiki/Heat_equation)? Không, nghiêm túc, bạn phải suy nghĩ về điều này cho mình - mặc dù phương trình nhiệt có thể cung cấp cho bạn một số ý tưởng. – Zeta

+0

cũng câu hỏi thực sự là loại phương trình tôi đang tìm kiếm, tôi giả sử Zeta trả lời này. Tôi không thực sự nóng về toán học và phương trình ở cấp độ này, tôi đã hy vọng một người nào đó có kinh nghiệm với điều này trước đây và tìm thấy một số blog hữu ích, v.v. –

Trả lời

49

Reddits công thức cũ và một chút thả ra

Về cơ bản, bạn có thể sử dụng công thức Reddit của. Kể từ khi hệ thống của bạn chỉ hỗ trợ upvotes bạn có thể cân nặng họ, dẫn đến một cái gì đó như thế này:

def hotness(track) 
    s = track.playedCount 
    s = s + 2*track.downloadCount 
    s = s + 3*track.likeCount 
    s = s + 4*track.favCount 
    baseScore = log(max(s,1)) 

    timeDiff = (now - track.uploaded).toWeeks 

    if(timeDiff > 1) 
     x = timeDiff - 1 
     baseScore = baseScore * exp(-8*x*x) 

    return baseScore 

Yếu tố exp(-8*x*x) sẽ cung cấp cho bạn thả mong muốn của bạn off:

Exponential drop off

Những điều cơ bản đằng sau

Bạn có thể sử dụng bất kỳ chức năng nào đi nhanh hơn số điểm của bạn. Vì chúng tôi sử dụng log trên điểm số của mình, ngay cả một hàm tuyến tính cũng có thể nhân lên (miễn là điểm của bạn không tăng theo cấp số nhân).

Vì vậy, tất cả những gì bạn cần là một hàm trả về 1 miễn là bạn không muốn sửa đổi điểm số và sau đó giảm xuống. Ví dụ của chúng tôi ở trên các biểu mẫu có chức năng:

multiplier(x) = x > 1 ? exp(-8*x*x) : 1 

Bạn có thể thay đổi hệ số nếu bạn muốn ít đường cong dốc hơn. varying multiplier

Ví dụ trong C++

Cho phép nói rằng xác suất cho một ca khúc đưa ra để được chơi trong một giờ nhất định là 50%, 10% tải, như 1% và 0,1% yêu thích. Sau đó, chương trình sau C++ sẽ cung cấp cho bạn một ước tính cho hành vi điểm số của bạn:

#include <iostream> 
#include <fstream> 
#include <random> 
#include <ctime> 
#include <cmath> 

struct track{ 
    track() : uploadTime(0),playCount(0),downCount(0),likeCount(0),faveCount(0){} 
    std::time_t uploadTime;  
    unsigned int playCount; 
    unsigned int downCount; 
    unsigned int likeCount; 
    unsigned int faveCount;  
    void addPlay(unsigned int n = 1){ playCount += n;} 
    void addDown(unsigned int n = 1){ downCount += n;} 
    void addLike(unsigned int n = 1){ likeCount += n;} 
    void addFave(unsigned int n = 1){ faveCount += n;} 
    unsigned int baseScore(){ 
     return playCount + 
      2 * downCount + 
      3 * likeCount + 
      4 * faveCount; 
    } 
}; 

int main(){ 
    track test; 
    const unsigned int dayLength = 24 * 3600; 
    const unsigned int weekLength = dayLength * 7;  

    std::mt19937 gen(std::time(0)); 
    std::bernoulli_distribution playProb(0.5); 
    std::bernoulli_distribution downProb(0.1); 
    std::bernoulli_distribution likeProb(0.01); 
    std::bernoulli_distribution faveProb(0.001); 

    std::ofstream fakeRecord("fakeRecord.dat"); 
    std::ofstream fakeRecordDecay("fakeRecordDecay.dat"); 
    for(unsigned int i = 0; i < weekLength * 3; i += 3600){ 
     test.addPlay(playProb(gen)); 
     test.addDown(downProb(gen)); 
     test.addLike(likeProb(gen)); 
     test.addFave(faveProb(gen));  

     double baseScore = std::log(std::max<unsigned int>(1,test.baseScore())); 
     double timePoint = static_cast<double>(i)/weekLength;   

     fakeRecord << timePoint << " " << baseScore << std::endl; 
     if(timePoint > 1){ 
      double x = timePoint - 1; 
      fakeRecordDecay << timePoint << " " << (baseScore * std::exp(-8*x*x)) << std::endl; 
     } 
     else 
      fakeRecordDecay << timePoint << " " << baseScore << std::endl; 
    } 
    return 0; 
} 

Kết quả:

Decay

Như vậy là đủ cho bạn.

+2

Cảm ơn bạn đã dành thời gian giải thích rõ ràng ... sẽ kiểm tra nó buổi tối với dữ liệu của tôi. –

+0

@Zeta Bạn đã tìm ra điểm kinh nghiệm như thế nào (-8 * x * x)? Tôi cần áp dụng điều này cho một vấn đề tương tự liên quan đến dấu thời gian 'created_at' và' updated_at' mà tôi sắp xếp theo 'updated_at' nhưng tôi cần nó thả sau 6 giờ khác biệt' created_at' và tôi không chắc cách tinh chỉnh công thức cho điều đó. – paulkon

+3

@paulkon có thể hơi trễ để trả lời ... hãy xem biểu đồ đầu tiên (biểu đồ màu đỏ) trong câu trả lời của Zeta: đây là biểu đồ cho điểm kinh nghiệm (-8 * x * x), hiển thị dòng bỏ được áp dụng cho baseScore một lần bản nhạc đã cũ hơn một tuần. Để nhận được tài khoản của bạn sau 6 giờ, bạn sẽ thực hiện một số việc như 'timeDiff = (now - track.created_at) .toHours' và sau đó:' if timeDiff> 6; x = timeDiff - 6; baseScore * = exp (-8 * x * x) '. Tinh chỉnh số 8 trong hàm mũ: giá trị càng cao, giá trị thả xuống càng cao :) Với -8: http://fooplot.com/plot/h0nfqukrj8 Với -50: http://fooplot.com/plot/e57bc1osnv –