c# - Python 到 C# 移植后的错误计算

标签 c# python math time port

我正在为基于 Reddit 模型的帖子系统开发时间衰减算法: http://amix.dk/blog/post/19588

我的工作端口在这里:

public class Calculation
{
    protected DateTime Epoch = new DateTime(1970, 1, 1);

    protected long EpochSeconds(DateTime dt)
    {
        var ts = dt.Subtract(Convert.ToDateTime("1/1/1970 8:00:00 AM"));

        return ((((((ts.Days * 24) + ts.Hours) * 60) + ts.Minutes) * 60) + ts.Seconds);
    }

    protected int Score(int upVotes, int downVotes)
    {
        return upVotes - downVotes;
    }

    public double HotScore(int upVotes, int downVotes, DateTime date)
    {
        var s = Score(upVotes, downVotes);
        var order = Math.Log(Math.Max(Math.Abs(s), 1), 10);
        var sign = Math.Sign(s);
        var seconds = EpochSeconds(date) - 1134028003;
        return Math.Round(order + sign * ((double)seconds / 45000), 7);
    }
}

根据所提供链接的模型输出,我应该会看到在 0-13 小时内逐渐衰减,然后急剧衰减。

我看到的是非常均匀的衰减,并且得分远高于原始代码的输出(原始代码:3480-3471)。

这是我的测试方法:

        Calculation c = new Calculation();
        double now = c.HotScore(100, 2, DateTime.Now);
        double fivehoursago = c.HotScore(100, 2, DateTime.Now.AddHours(-5));
        double tenhoursago = c.HotScore(100, 2, DateTime.Now.AddHours(-10));
        double elevenhoursago = c.HotScore(100, 2, DateTime.Now.AddHours(-11));
        double twelvehoursago = c.HotScore(100, 2, DateTime.Now.AddHours(-12));
        double thirteenhoursago = c.HotScore(100, 2, DateTime.Now.AddHours(-13));
        double fiftyhoursago = c.HotScore(100, 2, DateTime.Now.AddHours(-50));
        double onehundredhoursago = c.HotScore(100, 2, DateTime.Now.AddHours(-100));
        Console.WriteLine(now.ToString());
        Console.WriteLine(fivehoursago.ToString());
        Console.WriteLine(tenhoursago.ToString());
        Console.WriteLine(elevenhoursago.ToString());
        Console.WriteLine(twelvehoursago.ToString());
        Console.WriteLine(thirteenhoursago.ToString());
        Console.WriteLine(fiftyhoursago.ToString());
        Console.WriteLine(onehundredhoursago.ToString());
        Console.ReadLine();

输出值:

now:               4675.2993816
five hours:        4674.8993816
ten hours:         4674.4993816
eleven hours:      4674.4193816
twelve hours:      4674.3393816
thirteen hours:    4674.2593816
fifty hours:       4671.2993816
one-hundred hours: 4667.2993816

显然,它工作正常,但有些地方不对劲。这可能与缺乏真正的 *nix Epoch 支持有关,或者缺乏类似的微秒计算,但有些事情不太正确。

可能的引用资源: http://blogs.msdn.com/b/brada/archive/2004/03/20/93332.aspx http://codeclimber.net.nz/archive/2007/07/10/convert-a-unix-timestamp-to-a-.net-datetime.aspx

最佳答案

您的主要问题是热门算法是时间相关的。您在 DateTime.Now 计算热门得分,而该文章是在 2010 年 11 月 23 日撰写的(请查看文章底部)。

经过反复试验,数据似乎是在大约 2010-11-23 07:35 计算的。尝试使用该值而不是 DateTime.Now,您应该得到与图中所示数据大致相同的结果。

请注意,您可以对代码进行以下改进:

public class Calculation
{
    private static readonly DateTime Epoch = new DateTime(1970, 1, 1);

    private double EpochSeconds(DateTime dt)
    {
        return (dt - Epoch).TotalSeconds;
    }

    private int Score(int upVotes, int downVotes)
    {
        return upVotes - downVotes;
    }

    public double HotScore(int upVotes, int downVotes, DateTime date)
    {
        int s = Score(upVotes, downVotes);
        double order = Math.Log(Math.Max(Math.Abs(s), 1), 10);
        int sign = Math.Sign(s);
        double seconds = EpochSeconds(date) - 1134028003;
        return Math.Round(order + sign * seconds / 45000, 7);
    }
}

我的结果:

3479.0956039
3478.6956039
3478.2956039
3478.2156039
3478.1356039
3478.0556039
3475.0956039
3471.0956039

变化:

  • 使用声明的纪元而不是 1970-01-01 08:00:00 的转换(我认为 08:00 是一个错误)。
  • 您可以使用a - b减去两个日期;它与 a.Subtract(b) 相同,但更简洁,并且反射(reflect)了原始 Python 代码。
  • 时间跨度确实为您提供微秒精度(刻度是最小单位,等于 100 纳秒)。
  • 此外,TotalSeconds 还提供一个时间跨度内的总秒数;无需重新计算。小数部分甚至可以为您提供微秒精度。
  • 通过从 EpochSeconds 返回 double,您可以保持此精度。
  • 使数据类型显式化,而不是var,以清楚地指示变量是什么(它们与方法签名匹配,因此没有隐式向上转换)。
  • 将不需要的 protected 更改为 private 并将 Epoch 设为常量。

关于c# - Python 到 C# 移植后的错误计算,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11855423/

相关文章:

loops - 快速计算最大值的最有效方法

c# - 如何通过在页面上显示半透明控件来禁用Windows Phone上的所有控件?

c# - 需要验证数据契约(Contract)和数据成员

c# - 创建插件应用程序的方法

c# - Regex.Split() 在逗号、空格或分号分隔的字符串上

带有装饰器的动态方法创建者的python setattr

python - 二进制响应内容,请求库

r - 使用 R 的 LU 分解

python - 将这个简单的 block 转换为惯用的 Python 代码

c# - 在 .NET 中求解方程