从pandas列中获取唯一月份列表

4
假设我有以下Pandas的date_range
rng = pd.date_range('9/1/2017', '12/31/2017')

我想获取一个唯一月份的列表。目前为止,我想到了以下方法,但肯定有更好的方法:

df = pd.DataFrame({'date': rng})
months = df.groupby(pd.Grouper(key='date', freq='M')).agg('sum').index.tolist()
formatted_m = [i.strftime('%m/%Y') for i in months]
# ['09/2017', '10/2017', '11/2017', '12/2017']

请注意,日期将存储在DataFrame列或索引中。

请问您是在询问哪个解决方案? - Anton vBR
更新了问题。 - Johnny Metz
4个回答

9

使用numpy.unique,因为DatetmeIndex.strftime返回numpy数组

rng = pd.date_range('9/1/2017', '12/31/2017')
print (np.unique(rng.strftime('%m/%Y')).tolist())
['09/2017', '10/2017', '11/2017', '12/2017']

如果输入是 DataFrame 的一列,请使用Anton vBR的解决方案
print(df['date'].dt.strftime("%m/%y").unique().tolist())

或者使用 drop_duplicates 方法:
print(df['date'].dt.strftime("%m/%y").drop_duplicates().tolist())

时间:

所有解决方案的性能相同 - 去重(unique)与删除重复(drop_duplicates):

rng = pd.date_range('9/1/1900', '12/31/2017')

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

In [54]: %timeit (df['date'].dt.strftime("%m/%y").unique().tolist())
1 loop, best of 3: 469 ms per loop

In [56]: %timeit (df['date'].dt.strftime("%m/%y").drop_duplicates().tolist())
1 loop, best of 3: 466 ms per loop

该死..我认为这一定要再快一点!..但是等等..你正在调用范围而不是数据框列。我想范围只是用来创建数据样本的。 - Anton vBR
好的,现在你加入了我的解决方案 +1 :) - Anton vBR
最好是删除代码,只留下链接,这样更好吗?还是有其他更好的选择? - jezrael
我不介意。我认为 OP 正在询问我的解决方案。让我们看看。 - Anton vBR
@AntonvBR 你说得对。这个范围只是用来构建DataFrame的。不过,感谢你提供了完整的答案! - Johnny Metz
@JohnnyMetz 我们很高兴能够帮忙。不过这次我赢了 :p。我认为在这种情况下 drop_duplicates 并不是真正必要的,因为它并没有增加任何额外的价值(反而降低可读性)。 - Anton vBR

5

是或者这个:

df['date'].dt.strftime("%m/%y").unique().tolist()
#['09/17', '10/17', '11/17', '12/17']

1
不需要构建df
(rng.year*100+rng.month).value_counts().index.tolist()
Out[861]: [201712, 201710, 201711, 201709]

更新:

set((rng.year*100+rng.month).tolist())
Out[865]: {201709, 201710, 201711, 201712}

有点不同,但加1 :) - jezrael
@jezrael,对于value_counts有一点不同的地方 :-) - BENY
我认为这是聪明但不必要的,因为unique()可能更快。如果您需要数量,则这很好。 - Anton vBR
我喜欢这个集合解决方案。然而,我仍然认为这是错误的,因为 OP 正在要求列操作而不是范围操作。我的猜测。 - Anton vBR
@Wen - set 函数存在问题,你需要排序并使用更多的数据进行检查。 - jezrael

0

我通常使用这个,我认为它非常直观:

rng.month.unique()

编辑:可能不再相关,但为了完整起见:

set([str(year)+str(month) for year , month in zip(rng.year,rng.month)])

这是错误的,因为它只考虑了月份。我们需要考虑月份和年份。 - Anton vBR
我刚刚读到他/她想要一个唯一月份的列表 :( 必须更仔细地阅读帖子! - Michael Xu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接