pd.Grouper() 应用于日期时间时,更改原始日期列
Posted
技术标签:
【中文标题】pd.Grouper() 应用于日期时间时,更改原始日期列【英文标题】:pd.Grouper() when applied on datetime, changes the original column of dates 【发布时间】:2021-12-18 19:42:12 【问题描述】:我的巨大数据框中有一个示例数据框,如下所示。
import pandas as pd
import numpy as np
NaN = np.nan
data =
'ID':['AAQRB','AAQRB','AAQRB',
'AHXSJ','AHXSJ','AHXSJ','GABOY','GABOY','GABOY','GHZGS','GHZGS','GHZGS'],
'Date':['10/18/2021 10:52:53 PM','10/18/2021 10:53:55 PM', '10/25/2021 5:55:43 PM',
'10/22/2021 10:37:06 PM','10/22/2021 10:38:22 PM','10/22/2021 10:39:56 PM',
'11/1/2021 1:27:15 AM','11/1/2021 1:28:45 AM','11/2/2021 8:53:39 PM',
'10/29/2021 11:13:57 PM', '10/29/2021 11:17:47 PM', '10/29/2021 11:19:15 PM'],
'Race_x':[NaN,NaN,NaN,NaN,NaN,1,NaN,NaN,1, NaN,NaN,1],
'Vaccine':['TRUE',NaN,NaN,'TRUE',NaN,NaN,'TRUE',NaN,NaN,'FALSE',NaN,NaN],
'Study_activity':
[NaN,'continue',NaN,NaN,'continue',NaN,NaN,'continue',NaN,NaN,'continue',NaN],
'Who_Contacted':
[NaN,NaN,'WeContacted',NaN,NaN,'WeContacted',NaN,NaN,NaN,NaN,NaN,'WeContacted']
test_df = pd.DataFrame(data)
目标是获取每个 ID 的所有第一个值,并将参与者的几行过滤为包含所有信息的单行。最终的数据框应如下图所示。
代码尝试
我尝试使用 Grouper() 函数,代码如下。
test_df['Date'] = pd.to_datetime(test_df['Date'])
test_df1 = (test_df.groupby(['ID', pd.Grouper(key='Date', freq='D')])
.agg("first")
.reset_index())
baseline_df = test_df1[~test_df1.duplicated(subset = ['ID'], keep='first')]
但问题是,如果我使用 freq='D',那么第二天输入的 Race_x 值就会丢失。输出如下图所示。
如果我使用 freq='M' 或 freq='Y',则会捕获其他值,但 Dates 列的值会发生变化,我们会得到每个 ID 的月末日期,如下所示。
最后的“日期”列应该是每个 ID 的“日期”的第一个条目,并且不应更改。
非常感谢任何帮助。谢谢!
【问题讨论】:
【参考方案1】:创建一个按月分组的虚拟列:
>>> test_df.assign(month=test_df['Date'].dt.strftime('%Y-%m')) \
.groupby(['ID', 'month']).agg('first') \
.droplevel(1).reset_index() \
.assign(Date=lambda x: x['Date'].dt.date)
ID Date Race_x Vaccine Study_activity Who_Contacted
0 AAQRB 2021-10-18 NaN TRUE continue WeContacted
1 AHXSJ 2021-10-22 1.0 TRUE continue WeContacted
2 GABOY 2021-11-01 1.0 TRUE continue None
3 GHZGS 2021-10-29 1.0 FALSE continue WeContacted
【讨论】:
这为每个 ID 提供 2 或 3 行。我的目标是为每个参与者获得一行。这只是一个庞大数据集的样本,每个 ID 至少有 30 个条目,必须合并到一行。 在 agg 函数中做你想做的事,但你的问题是pd.Grouper
,不是吗?
是的。它是。即使在我过滤到您上面给出的格式之后,它也会是同样的问题。
这可以在“年”而不是“月”中完成吗?并得到相同的结果?如果是这样,代码中需要更改什么?
是的。这是正确的。我做到了,而且效果很好。谢谢【参考方案2】:
看起来您只想将 groupby
ID 和 Date
聚合为第一,其他一切都与您拥有有效值时一样。
假设所有Race_x
、Vaccine
、Study_activity
、Who_Contacted
始终是 ID 的单个非 NaN 值。聚合前可以先bfill
。
这会将非 NaN 值收集到参与者的第一个条目。
test_df['Date'] = pd.to_datetime('Date').dt.date
test_df.update(test_df.groupby('ID').bfill())
然后,尝试聚合。
test_df.groupby('ID').first().reset_index()
>>> ID Date Race_x Vaccine Study_activity Who_Contacted
0 AAQRB 2021-10-18 NaN TRUE continue WeContacted
1 AHXSJ 2021-10-22 1.0 TRUE continue WeContacted
2 GABOY 2021-11-01 1.0 TRUE continue NaN
3 GHZGS 2021-10-29 1.0 FALSE continue WeContacted
【讨论】:
不错的解决方案。但不幸的是,它没有为原始数据集提供所需的解决方案。最终的解决方案类似于 Corralien 在他的解决方案中的解决方案。 您能发布您的预期结果吗?我以为每个 ID 需要一行。 是的,但原始数据集不是单个非 NaN 值。这些值可以在后续行中重复。我认为这是 backfill() 不起作用的原因。问题中给出了预期的结果。 感谢您的更新。该解决方案是实现“获取每个 ID 的所有第一个值”。通过对每个 ID 执行bfill
,第一个非 NaN 值总是出现在 ID 的第一行。此结果看起来与您的预期结果完全相同。我错过了什么?也许,样本不能代表多个非 NaN 值的场景。以上是关于pd.Grouper() 应用于日期时间时,更改原始日期列的主要内容,如果未能解决你的问题,请参考以下文章
pyspark:在日期和时间上重新采样 pyspark 数据帧