将日期转换为浮点数以对 Pandas 数据框进行线性回归

Posted

技术标签:

【中文标题】将日期转换为浮点数以对 Pandas 数据框进行线性回归【英文标题】:Convert date to float for linear regression on Pandas data frame 【发布时间】:2014-08-26 15:03:57 【问题描述】:

似乎要让 OLS 线性回归在 Pandas 中正常工作,参数必须是浮点数。我从以下形式的 csv(称为“gameAct.csv”)开始:

date, city, players, sales

2014-04-28,London,111,1091.28

2014-04-29,London,100,1100.44

2014-04-28,Paris,87,1001.33

...

我想对销售如何依赖日期执行线性回归(随着时间的推移,销售如何变化?)。我下面的代码的问题似乎是日期不是浮点值。对于如何解决 Pandas 中的这个索引问题,我将不胜感激。

我当前的(不工作,但正在编译的代码):

import pandas as pd

from pandas import DataFrame, Series

import statsmodels.formula.api as sm

df = pd.read_csv('gameAct.csv')

df.columns = ['date', 'city', 'players', 'sales']

city_data = df[df['city'] == 'London']

result = sm.ols(formula = 'sales ~ date', data = city_data).fit()

当我改变城市值时,我得到 R^2 = 1 结果,这是错误的。我也尝试index_col = 0, parse_dates == True' 定义dataframe df,但没有成功。

我怀疑有一种更好的方法可以读取此类 csv 文件以对日期执行基本回归,以及进行更一般的时间序列分析。感谢您的帮助、示例和资源!

注意,使用上面的代码,如果我将日期索引(对于给定城市)转换为数组,则该数组中的值的形式为:

'\xef\xbb\xbf2014-04-28'

如何对所有非销售参数进行 AIC 分析? (例如,结果可能是销售额最线性地取决于日期和城市)。

【问题讨论】:

当然,一种非pythonic和类似unpandas的解决方案是以下形式: datecol = london['date'];朗达斯 = []; for x in datecol: londates.append(float(x.replace('-',''))) 然后在 londates 数组上回归指定的伦敦数据 【参考方案1】:

我不确定 statsmodels 的具体细节,但this post 列出了 python 的所有日期/时间转换。它们并不总是一对一的,所以这是我经常使用的参考;-)

【讨论】:

感谢您的参考,尽管我无法将其应用于我的具体问题。【参考方案2】:

对于这种回归,我通常将日期或时间戳转换为自数据开始以来的整数天数。

这可以很好地解决问题:

df = pd.read_csv('test.csv')
df['date'] = pd.to_datetime(df['date'])    
df['date_delta'] = (df['date'] - df['date'].min())  / np.timedelta64(1,'D')
city_data = df[df['city'] == 'London']
result = sm.ols(formula = 'sales ~ date_delta', data = city_data).fit()

此方法的优点是您可以确定回归中涉及的单位(天),而自动转换可能会隐式使用其他单位,从而在您的线性模型中创建令人困惑的系数。它还允许您将来自不同时间开始的多个销售活动的数据组合到您的回归中(例如,您对作为活动天数的函数的活动的有效性感兴趣)。如果您有兴趣衡量一年中的某天趋势,您也可以选择 1 月 1 日作为您的 0。选择您自己的 0 日期让您掌控一切。

还有证据表明 statsmodels 支持来自 pandas 的时间序列。您也可以将其应用于线性模型: http://statsmodels.sourceforge.net/stable/examples/generated/ex_dates.html

另外,一个简短的说明: 您应该能够直接从 csv 中自动读取列名,就像我发布的示例代码一样。在您的示例中,我看到 csv 文件第一行中的逗号之间有空格,导致列名如“日期”。删除空格,自动读取 csv 标头应该可以正常工作。

【讨论】:

谢谢。我目前收到此错误(我相信它源于您在“date_delta”上的第三行):result[mask] = op(x[mask], y) TypeError: unsupported operand type(s) for -: 'str'和 'str' 现在,如果我删除这个 'date_delta' 设置,那么它会编译,但问题是 len(result.params) = # of unique dates,而不是一个线性回归性能的参数数量。欢迎评论。 如果它可能有用:>> pd.version 嗯,这很有趣。我和你有相同版本的熊猫。听起来您的df['date'] 列仍然是str 类型。第二行 df['date'] = pd.to_datetime(df['date']) 应该负责将 strs 转换为日期对象。可能由于输入 csv 中的奇怪字符而失败。我注意到您粘贴的一些值看起来像 '\xef\xbb\xbf2014-04-28',在我看来,这看起来像是一些垃圾字符(可能来自不完美的 UTF-8 转换)。我建议清理输入并再试一次。 确实,问题在于具有奇怪间距的日期条目,例如“20140428”而不是“20140428”。前者以 '\xef\xbb\xbf20140428' 的形式返回,我无法直接将其转换为浮点数,而 Pandas 似乎也不能(这令人惊讶吗?)。是否有 UTF-8 技巧,以便 Pandas 为我清理这些条目?我会尝试一些临时清洁,很快就会回来 我的临时解决方案采用了 s = ''.join(j for j in x if j.isdigit()),迭代日期条目 x,然后是浮点数。这和你的 cmets 让我找到了一个可行的解决方案。我仍然会对处理这种浮点转换的更优雅的方法感兴趣。再次感谢【参考方案3】:
df.date.dt.total_seconds()

如果您的日期数据类型是datetime64[ns],那么dt.total_seconds() 应该可以工作;这将返回秒数(浮点数)。

【讨论】:

【参考方案4】:

获取日期为浮点年份

我更喜欢日期格式,无需上下文即可理解。因此,浮点年份表示。 这里的好处是,该解决方案适用于 numpy 级别 - 因此应该很快。

import numpy as np
import pandas as pd

def dt64_to_float(dt64):
    """Converts numpy.datetime64 to year as float.

    Rounded to days

    Parameters
    ----------
    dt64 : np.datetime64 or np.ndarray(dtype='datetime64[X]')
        date data

    Returns
    -------
    float or np.ndarray(dtype=float)
        Year in floating point representation
    """

    year = dt64.astype('M8[Y]')
    # print('year:', year)
    days = (dt64 - year).astype('timedelta64[D]')
    # print('days:', days)
    year_next = year + np.timedelta64(1, 'Y')
    # print('year_next:', year_next)
    days_of_year = (year_next.astype('M8[D]') - year.astype('M8[D]')
                    ).astype('timedelta64[D]')
    # print('days_of_year:', days_of_year)
    dt_float = 1970 + year.astype(float) + days / (days_of_year)
    # print('dt_float:', dt_float)
    return dt_float

if __name__ == "__main__":

    dates = np.array([
        '1970-01-01', '2014-01-01', '2020-12-31', '2019-12-31', '2010-04-28'],
        dtype='datetime64[D]')

    df = pd.DataFrame(
        'date': dates,
        'number': np.arange(5)
        )

    df['date_float'] = dt64_to_float(df['date'].to_numpy())
    print('df:', df, sep='\n')
    print()

    dt64 = np.datetime64( "2011-11-11" )
    print('dt64:', dt64_to_float(dt64))

输出

df:
        date  number   date_float
0 1970-01-01       0  1970.000000
1 2014-01-01       1  2014.000000
2 2020-12-31       2  2020.997268
3 2019-12-31       3  2019.997260
4 2010-04-28       4  2010.320548

dt64: 2011.8602739726027

【讨论】:

以上是关于将日期转换为浮点数以对 Pandas 数据框进行线性回归的主要内容,如果未能解决你的问题,请参考以下文章

ValueError:无法将字符串转换为浮点数:Python中的“lisans”

将文本转换为浮点数/整数/日期时,Delphi 消息“您已插入无效值”

Pyspark 数据框将多列转换为浮点数

将 pandas.Series 从 dtype 对象转换为浮点数,将错误转换为 nans

Pandas / 如何将存储为字符串的科学记数法转换为浮点数?

Pandas - 将值作为字符串类型转换为浮点数