所以我有一个用水数据集,其中包含我想要操作的3个关键列,如下所示:
meter_read_date meternumber consumption
0 1/25/2011 1 4320
1 2/22/2011 1 3800
2 3/28/2011 1 4440
3 4/29/2011 1 4440
4 6/6/2011 1 5320
5 6/9/2011 1 20214
6 7/30/2011 1 20214
7 8/30/2011 1 2952
8 9/30/2011 1 3684
9 10/29/2011 1 3374
10 11/27/2011 1 3866
11 12/27/2011 1 3470
12 1/25/2011 3 5900
13 2/22/2011 3 5720
14 3/28/2011 3 7320
15 4/28/2011 3 6360
16 6/6/2011 3 9420
17 7/5/2011 3 8120
18 8/2/2011 3 8520
19 9/3/2011 3 6740
20 10/10/2011 3 6820
21 11/7/2011 3 5720
22 12/1/2011 3 3940
23 12/29/2011 3 6260
我想按日历月计算每个米数的使用情况,我认为这涉及到平均每日价值,然后将总和汇总到月度范围。
澄清一下,第1行的消耗量为3800.这意味着2011年2月22日消费量为3800,自2011年1月25日之前的测量结果以来,我们知道3800加仑的用水量已经发生从2011年1月26日至2011年2月22日。我想知道日历月的消费,所以我会这样做:
2011年1月26日消费 - 2011年2月22日= 28天内3800加仑= ~146.2加仑/天
消费从2011年2月23日 - 2011年3月28日= 4440加仑超过34天= ~130.6加仑/天
因此,估计消耗量从2/1 - 2/28 = 146.2加仑/天和2 / 1-2 / 22和130.6加仑/天从2 / 23-2 / 28 = 3216.4 + 783.6 = 4000加仑日历月
我还没有能够想到一种有效的方法来做到这一点而没有嵌套循环,我真的不会在100万大小的数据集上使用它。 有什么想法吗?
如果有任何其他信息我可以发帖给我,请告诉我。
答案 0 :(得分:1)
这应该做你想要的大部分,虽然它不会是最有效的内存方式。我将在下面详细说明。
第一步是弄清楚每日消费。
df.meter_read_date = pd.to_datetime(df.meter_read_date)
df['days_since'] = df.groupby('meternumber').meter_read_date.diff()
df = df.set_index('meter_read_date')
df['daily_consumption'] = df.consumption / df.days_since.dt.days
现在,第一个仪表的数据框看起来像这样。
meternumber consumption days_since daily_consumption
meter_read_date
2011-01-25 1 4320 NaT NaN
2011-02-22 1 3800 28 days 135.714286
2011-03-28 1 4440 34 days 130.588235
2011-04-29 1 4440 32 days 138.750000
2011-06-06 1 5320 38 days 140.000000
2011-06-09 1 20214 3 days 6738.000000
2011-07-30 1 20214 51 days 396.352941
2011-08-30 1 2952 31 days 95.225806
2011-09-30 1 3684 31 days 118.838710
2011-10-29 1 3374 29 days 116.344828
2011-11-27 1 3866 29 days 133.310345
2011-12-27 1 3470 30 days 115.666667
此时至少有两种方法可以继续。最节省内存的方法是计算每组消费的比例,但这远非直截了当,尤其是因为您的数据每月可能有多于或少于一个读数。所以这种方式是(1)可能的,(2)记忆效率高,(3)相对较难。
另一种方式更容易,并且使用resample
转换为每日观察并回填每日消费。
df_daily = df.groupby('meternumber')['daily_consumption'].resample(
'1d',fill_method='bfill').reset_index()
这里的缺点是我们每天都有观察,对记忆施加更多压力,但它会自动解决很多问题 - 无需担心每个月有多少天或者每个月有多少读数。这里有几行,以其中一个读数为中心。
meternumber meter_read_date 0
27 1 2011-02-21 135.714286
28 1 2011-02-22 135.714286
29 1 2011-02-23 130.588235
30 1 2011-02-24 130.588235
从那里,你所要做的就是聚合。 (请注意,第一个月和最后一个月基于部分数据,您可能希望放弃它们或按比例计算每日消费量。)
df_daily['month'] = df_daily.meter_read_date.dt.month
df_daily.reset_index().groupby(['meternumber','month'])[0].sum()
meternumber month
1 1 950.000000
2 3769.243697
3 4072.720588
4 4163.750000
5 4340.000000
6 29377.411765
7 11985.814042
8 2975.612903
9 3565.161290
10 3640.620690
11 3946.379310
12 3123.000000
3 1 1430.000000
2 5786.050420
3 6643.719165
4 6227.593052
5 7487.692308
6 8169.230769
7 9311.428571
8 6716.696429
9 5608.631757
10 6133.243243
11 5205.833333
12 6424.166667
关于替代方法的一些简短想法:如果上述原因引起记忆问题,我认为可能存在混合方法。基本上,在计算每日消费量后,通过添加每个月的第一天和最后一天进行部分重新采样。从那里你可以以类似的方式聚合,虽然你需要基本上做加权和而不是简单的总和。
编码仍然比上述方法更难,但在内存上会更容易。尽管如此,这样做应该会大大简化编码,因为每一行现在都属于特定的月份,你不必尝试在不同月份分割读数。
答案 1 :(得分:0)
假设您的数据框名称为df,而meter_read_date是字符串/对象类型。由于数据框有一个日期列,并且您希望按月进行一些计算,因此最好将日期列转换为日期时间(如果不是)并将列设置为索引。
from dateutil.parser import parse
# convert meter_read_date to datetime
df['meter_read_date'] = df.meter_read_date.apply(parse)
df = df.set_index(['meter_read_date'])
# so you can group by year month and do some calculations
# a datetime index have a convenient way to get its element:year,month,day, etc
df.groupby([df.index.year,df.index.month,'meternumber'])['consumption'].mean()
# the result is :
meternumber
2011 1 1 4320
3 5900
2 1 3800
3 5720
3 1 4440
3 7320
4 1 4440
3 6360
6 1 12767
3 9420
7 1 20214
3 8120
8 1 2952
3 8520
9 1 3684
3 6740
10 1 3374
3 6820
11 1 3866
3 5720
12 1 3470
3 5100
Name: consumption, dtype: int64
答案 2 :(得分:0)
首先,让我们在指示月份添加一列。如果您的日期列是字符串,请使用方法A.如果是日期时间或时间戳,请使用方法B.
方法A:
df['month'] = df.meter_read_date.apply(lambda date_str: date_str.split("/")[0])
方法B:
df['month'] = pd.to_datetime(df.meter_read_date).apply(lambda date: date.month)
现在,您只需要在仪表ID和新创建的月份上执行groupby
。
gb = pd.DataFrame(df.groupby(['meternumber', 'month']).consumption.mean())
>>> gb
consumption
meternumber month
1 1 4320
2 3800
3 4440
4 4440
6 12767
7 20214
8 2952
9 3684
10 3374
11 3866
12 3470
3 1 5900
2 5720
3 7320
4 6360
6 9420
7 8120
8 8520
9 6740
10 6820
11 5720
12 5100
您还可以查看相对于所有仪表的此数据,以帮助识别具有高于平均值的那些仪表。用法:
gb['monthly_avg'] = gb.reset_index().groupby('month').consumption.transform('mean').values
gb['relative_usage'] = gb.consumption / gb.monthly_avg
>>> gb
consumption monthly_avg relative_usage
meternumber month
1 1 4320 5110.0 0.845401
2 3800 4760.0 0.798319
3 4440 5880.0 0.755102
4 4440 5400.0 0.822222
6 12767 11093.5 1.150854
7 20214 14167.0 1.426837
8 2952 5736.0 0.514644
9 3684 5212.0 0.706830
10 3374 5097.0 0.661958
11 3866 4793.0 0.806593
12 3470 4285.0 0.809802
3 1 5900 5110.0 1.154599
2 5720 4760.0 1.201681
3 7320 5880.0 1.244898
4 6360 5400.0 1.177778
6 9420 11093.5 0.849146
7 8120 14167.0 0.573163
8 8520 5736.0 1.485356
9 6740 5212.0 1.293170
10 6820 5097.0 1.338042
11 5720 4793.0 1.193407
12 5100 4285.0 1.190198