2012-02-14 16 views
8

Tôi có ứng dụng Django mà tôi cần triển khai một thuật toán xếp hạng/xếp hạng đơn giản. Tôi bị lạc như một:Quyết định và triển khai thuật toán xu hướng ở Django

Tôi có hai kiểu máy, BookReader. Mỗi đêm, sách mới được thêm vào cơ sở dữ liệu của tôi. Số lượng người đọc cho mỗi cuốn sách được cập nhật quá mỗi đêm, tức là một cuốn sách sẽ có nhiều bản ghi thống kê của người đọc (một bản ghi cho mỗi ngày).

Trong một khoảng thời gian nhất định (tuần trước, tháng trước hoặc năm trước), tôi muốn liệt kê những cuốn sách phổ biến nhất, tôi nên sử dụng thuật toán nào cho điều này?

Mức độ phổ biến không cần phải theo thời gian thực theo bất kỳ cách nào vì số người đọc cho mỗi cuốn sách chỉ được cập nhật hàng ngày.

Tôi đã tìm thấy một bài viết được tham chiếu trong một SO post that showed how they calculated trending Wikipedia articles khác nhưng bài đăng chỉ cho biết cách tính xu hướng hiện tại.

Như ai đó đã chỉ ra trên SO, nó là một thuật toán xu hướng cơ bản rất đơn giản và chỉ tính toán độ dốc giữa hai điểm dữ liệu vì vậy tôi đoán nó cho thấy xu hướng giữa ngày hôm qua và ngày hôm nay.

Tôi không tìm kiếm một uber phức tạp thuật toán xu hướng giống như những người sử dụng trên Hacker News, Reddit, vv

Tôi chỉ có hai trục dữ liệu, số lượng người đọc và ngày.

Bất kỳ ý tưởng nào về cách thức và cách thức tôi nên triển khai. Đối với một người không bao giờ làm việc với bất kỳ thống kê/thuật toán liên quan, điều này có vẻ là một cam kết rất khó khăn.

Cảm ơn mọi người trước.

Trả lời

5

Có lẽ có thể xu hướng "thuật toán" đơn giản nhất tôi có thể nghĩ đến là n-ngày di chuyển trung bình.Tôi không chắc chắn như thế nào dữ liệu của bạn có cấu trúc, nhưng nói rằng bạn có một cái gì đó như thế này:

books = {'Twilight': [500, 555, 580, 577, 523, 533, 556, 593], 
     'Harry Potter': [650, 647, 653, 642, 633, 621, 625, 613], 
     'Structure and Interpretation of Computer Programs': [1, 4, 15, 12, 7, 3, 8, 19] 
     } 

Một SMA chỉ mất n giá trị cuối cùng và trung bình họ:

def moving_av(l, n): 
    """Take a list, l, and return the average of its last n elements. 
    """ 
    observations = len(l[-n:]) 
    return sum(l[-n:])/float(observations) 

Ký hiệu lát chỉ cần lấy đuôi của danh sách, bắt đầu từ biến thứ n đến biến cuối cùng. Một trung bình di chuyển là một cách khá tiêu chuẩn để làm mịn ra bất kỳ tiếng ồn mà một cành hoặc nhúng duy nhất có thể giới thiệu. Chức năng có thể được sử dụng như vậy:

book_scores = {} 
for book, reader_list in books.iteritems(): 
    book_scores[book] = moving_av(reader_list, 5) 

Bạn sẽ muốn chơi xung quanh với số ngày trung bình. Và nếu bạn muốn nhấn mạnh các xu hướng gần đây, bạn cũng có thể xem bằng cách sử dụng một cái gì đó giống như một số weighted moving average.

Nếu bạn muốn tập trung vào cái gì mà có vẻ ít ở độc giả tuyệt đối và tập trung thay vì trên sự gia tăng độc giả, chỉ cần tìm ra sự thay đổi phần trăm trong 30 ngày di chuyển trung bình và 5 ngày di chuyển trung bình:

d5_moving_av = moving_av(reader_list, 5) 
d30_moving_av = moving_av(reader_list, 30) 
book_score = (d5_moving_av - d30_moving_av)/d30_moving_av 

Với những công cụ đơn giản này, bạn có một số lượng công bằng về tính linh hoạt trong số lượng bạn nhấn mạnh xu hướng trong quá khứ và số tiền bạn muốn làm mịn (hoặc không mượt mà) gai.

+0

HI Wilduck, Tôi đã xem xét tính toán EWMA mà bạn đã quy định. Điều đó có vẻ thích hợp cho vấn đề của tôi. Tôi đang bối rối như thế nào để tính toán giá trị của alpha 'α'. Bạn có bất kỳ ý tưởng làm thế nào tôi có thể tính toán này? –

+0

@MridangAgarwalla Tin tốt! Bạn không cần phải tính toán nó! Bạn có thể chọn bất kỳ số nào giữa 0 và 1, trong đó một số gần hơn với một lần giảm giá quan sát cũ nhanh hơn. Sự lựa chọn của bạn sẽ phụ thuộc vào số tiền bạn muốn giảm giá trị cũ hơn, vì vậy bạn có thể chơi với nó cho đến khi bạn tìm thấy một cái gì đó bạn thích. – Wilduck

+0

Điều đó đang được nói, tôi nghĩ rằng một trung bình di chuyển đơn giản (một trong đó không phải là trọng số theo cấp số nhân) có thể làm việc chỉ là tốt cho các mục đích của bạn. Tôi khuyên bạn nên triển khai phiên bản đơn giản trước, và sau đó hoán đổi trong phiên bản có trọng số theo cấp số nhân nếu bạn thấy nó không thỏa đáng. – Wilduck

0

Mức độ phổ biến thật dễ dàng; bạn chỉ cần đếm số lượng người đọc và đơn đặt hàng theo đó:

Book.objects.annotate(reader_count=Count('readers')).order_by('-reader_count') 

Xu hướng khó hơn vì đây là đồng bằng phổ biến hơn, tức là sách có nhiều người đọc gần đây nhất. Nếu bạn muốn một cái gì đó như thế này, bạn sẽ cần một cái gì đó chạy đằng sau hậu trường để giữ một bản ghi của người đọc đếm theo ngày.

0

Bạn có thể lấy stackoverflow reputation ranking làm ví dụ.

Người dùng có thể thay đổi quan điểm: theo tháng, theo năm, ....

Trong trường hợp của bạn: Cuốn sách đã đọc gần hết theo tháng, theo năm.

Để đạt được điều này, bạn nên lưu từng ngày số lượng người đọc cho mỗi cuốn sách.

reader(date, book, total) 

Sau đó, nó cũng đơn giản như:

Book.objects.filter( 
        boor__reader__date__gte = some_date 
        ).annotate(
          num_readers=Sum('book__reader__total') 
           ).order_by('-num_readers') 
+1

Không bao giờ làm điều này.Đây là cách dễ nhất để giết máy chủ sql. – iddqd

+0

@iddqd, Bạn có một chút khải huyền. Vui lòng liên kết một số tài nguyên giải thích câu của bạn. – danihp

+1

Chức năng tổng hợp rất chậm, quét toàn bộ rất chậm. Chức năng tổng hợp cộng với quét toàn bộ rất rất chậm. Để sản xuất mọi thứ hạng thời gian, bạn cần phải đọc tất cả dữ liệu. – iddqd

0

tôi sẽ làm điều đó có hệ thống như thế này:

  1. Tạo một danh sách các câu hỏi phổ biến nhất hoặc điểm dữ liệu người dùng sẽ quan tâm, ví dụ: 1.1 Top 100 sách Phổ biến nhất tuần này 1.2 Top 100 Sách phổ biến nhất trong tháng này

  2. Sau thông tin đọc/sách hàng ngày của bạn. được cập nhật, tôi sẽ chạy một công việc (có thể là hàng đêm) để cập nhật một bảng thông tin này. Bảng có thể sẽ có các trường Book và ReaderDelta trong đó ReaderDelta là sự thay đổi trong readerCount hơn một tuần, tháng hoặc năm.

  3. Bạn cũng có thể chỉ cần lưu trữ ReaderDelta hàng ngày và khi tìm kiếm giá trị dữ liệu của một tháng, chỉ cần tổng hợp 30 ngày qua theo ngày động.