通过星期Python遍历带有日期列的PD DF

时间:2018-08-08 15:10:13

标签: python pandas loops datetime

我有一个带有日期时间对象列的一个月DataFrame和一堆我想应用的功能-按周。因此,我想遍历DataFrame并将功能应用于每个星期。如何在每周的时间段内迭代?

我的DataFrame看起来像这样: enter image description here

这是一些随机的日期时间代码:

np.random.seed(123)
n = 500
df = pd.DataFrame(
        {'date':pd.to_datetime(
                  pd.DataFrame( { 'year':  np.random.choice(range(2017,2019), size=n),
                                  'month': np.random.choice(range(1,2),      size=n),
                                  'day':   np.random.choice(range(1,28),      size=n)
                                 } )
         ) }  
    )
df['random_num'] = np.random.choice(range(0,1000), size=n)

我的每周时长不一致(有时我每周有1000条推文,有时是100,000条)。能否有人给我一个例子,说明如何按周遍历此数据框? (我不需要聚合或groupby函数。)

3 个答案:

答案 0 :(得分:1)

如果您真的不想使用groupby和聚合,则:

for week in df['date'].dt.week.unique():
    this_weeks_data = df[df['date'].dt.week == week]

如果您拥有一年以上的数据,这当然会出错。

答案 1 :(得分:0)

给出示例数据框

    date        random_num
0   2017-01-01  214
1   2018-01-19  655
2   2017-01-24  663
3   2017-01-26  723
4   2017-01-01  974

首先,您可以尝试将索引设置为datetime对象,如下所示

df.set_index(df.date, inplace=True)
df.drop('date', axis=1, inplace=True)

这会将索引设置为日期列,并删除原始列。你会得到

>>> df.head()    
date        random_num
2017-01-01  214
2018-01-19  655
2017-01-24  663
2017-01-26  723
2017-01-01  974

然后,您可以使用熊猫groupby函数根据您的频率对数据进行分组,并应用您选择的任何函数。

# To group by week and count the number of occurances
>>> df.groupby(pd.Grouper(freq='W')).count().head()

date        random_num
2017-01-01  11
2017-01-08  65
2017-01-15  55
2017-01-22  66
2017-01-29  45

# To group by week and sum the random numbers per week
>>> df.groupby(pd.Grouper(freq='W')).sum().head()       

date        random_num
2017-01-01  7132
2017-01-08  33916
2017-01-15  31028
2017-01-22  31509
2017-01-29  22129

您还可以使用熊猫的myFunction方法来应用任何通用函数apply

df.groupby(pd.Grouper(freq='W')).apply(myFunction)

如果要在分组后将函数myFunction应用于任何特定的列columnName,也可以按照以下步骤进行操作

df.groupby(pd.Grouper(freq='W'))[columnName].apply(myFunction)

答案 2 :(得分:0)

[已解决多年]

pd.Grouper(freq='W')可以正常工作,但有时我会遇到一些与周数不均时如何拆分周数有关的不良行为。因此,这就是为什么我有时喜欢像本示例中所示手动进行周拆分。

因此,拥有跨越多年的数据集

import numpy as np
import pandas as pd
import datetime

# Create dataset
np.random.seed(123)
n = 100000

date = pd.to_datetime({
    'year': np.random.choice(range(2017, 2020), size=n),
    'month': np.random.choice(range(1, 13), size=n),
    'day': np.random.choice(range(1, 28), size=n)
})

random_num = np.random.choice(
    range(0, 1000),
    size=n)

df = pd.DataFrame({'date': date, 'random_num': random_num})

例如:

print(df.head())
        date  random_num
0 2019-12-11         413
1 2018-06-08         594
2 2019-08-06         983
3 2019-10-11          73
4 2017-09-19          32

首先创建一个帮助程序索引,该索引使您可以按周(还考虑年份)进行迭代:

df['grp_idx'] = df['date'].apply(
    lambda x: '%s-%s' % (x.year, '{:02d}'.format(x.week)))

print(df.head())
        date  random_num  grp_idx
0 2019-12-11         413  2019-50
1 2018-06-08         594  2018-23
2 2019-08-06         983  2019-32
3 2019-10-11          73  2019-41
4 2017-09-19          32  2017-38

然后只应用对每周子集进行计算的函数,就像这样:

def something_to_do_by_week(week_data):
    """
    Computes the mean random value.
    """

    return week_data['random_num'].mean()



weekly_mean = df.groupby('grp_idx').apply(something_to_do_by_week)
print(weekly_mean.head())

grp_idx
2017-01    515.875668
2017-02    487.226704
2017-03    503.371681
2017-04    497.717647
2017-05    475.323420

一旦有了每周指标,您可能希望返回实际日期,该日期比年周指数更有用:

def from_year_week_to_date(year_week):
    """
    """

    year, week = year_week.split('-')
    year, week = int(year), int(week)

    date = pd.to_datetime('%s-01-01' % year)
    date += datetime.timedelta(days=week * 7)

    return date


weekly_mean.index = [from_year_week_to_date(x) for x in weekly_mean.index]

print(weekly_mean.head())
2017-01-08    515.875668
2017-01-15    487.226704
2017-01-22    503.371681
2017-01-29    497.717647
2017-02-05    475.323420
dtype: float64

最后,现在您可以绘制带有可解释日期的漂亮图了: enter image description here

就像进行健全性检查一样,使用pd.Grouper(freq='W')进行的计算给了我几乎相同的结果(不知何故,它在pd.Series的开头增加了一周的时间)

df.set_index('date').groupby(
    pd.Grouper(freq='W')
).mean().head()
Out[27]: 
            random_num
date                  
2017-01-01  532.736364
2017-01-08  515.875668
2017-01-15  487.226704
2017-01-22  503.371681
2017-01-29  497.717647