【问题标题】:Pandas, groupby absolute month熊猫,按绝对月份分组
【发布时间】:2014-12-15 04:55:12
【问题描述】:

问题:给定一个包含多个条目的数据框和 %Y%m%d 形式的“日期”列(即 yyyy-mm-dd;这些条目以字符串形式出现)什么是一种计算快速的方法来向包含月份字典顺序的数据框中添加一列?

为什么在 StackOverflow 上:给定指定的年份和月份,上述排序允许相对于指定月份轻松上升或下降任意月数。我有一个有效的临时解决方案,但想象一下这个问题之前已经很好地解决了。

上下文:举例来说,给定数据框df:

         date  user
0  2011-10-06     1
1  2011-09-01     2
2  2011-11-05     3
3  2012-01-01     1
4  2012-01-01     2
5  2012-01-02     3

想要的输出是:

         date  user  absmonth
0  2011-10-06     1         2
1  2011-09-01     2         1
2  2011-11-05     3         3
3  2012-01-01     1         4
4  2012-01-01     2         4
5  2012-01-02     3         4

我的尝试:

1) 我做了一个临时定义,它根据简单的算术设置“absmonth”的值;每行通过df.loc[row, 'absmonth'] = ...。这“有效”,但在计算上非常很慢。

2) 使用 groupby:

df['newdate']=pd.to_datetime(df['date'],format='%Y-%m-%d') 
df = df.set_index('newdate')
monthsgroup = df.groupby(df.index.month, df.index.year)

产生错误:

    axis = self._AXIS_ALIASES.get(axis, axis)
TypeError: unhashable type: 'numpy.ndarray'

还有:

months = df.gropuby(df.index.month)
len(months)
4

此时,我应该可以使用 months 在 df 上使用类似“应用”功能的东西,但我有点迷失了......

ps:

pd.__version__
'0.14.0'

感谢您的帮助。

【问题讨论】:

  • 不确定月份的字典顺序是什么意思?用英文拼出的月份是按字母顺序排列的吗?
  • 所有数字对(Y,m)的集合上的字典。 IE。我们写 "(Y,m)

标签: python-2.7 pandas group-by dataframe


【解决方案1】:

我认为“申请”是一个不错的选择。

我从头到尾提供我当前的解决方案。我想我已经通过现在应用“min”方法来固定排名以获得所需的结果。

import pandas as pd

x = [{'date':'2011-10-06', 'user':1}, {'date':'2011-09-01', 'user':2},{'date':'2011-11-05', 'user':3}, {'date':'2012-01-01', 'user':1},{'date':'2012-01-01', 'user':2}, {'date':'2012-01-02', 'user':3}]

dx = pd.DataFrame(x)

dx['date'] = pd.to_datetime(dx['date'], format='%Y-%m-%d')

def get_ym(s):
  s = str(s)
  s = s[:7]
  s = s.replace('-','')
  return int(s)


dx['absmonth'] = dx['date'].apply(get_ym)
dx['absmonth'] = dx['absmonth'].rank(method='min')

-----
dx = 
        date  user  absmonth
0 2011-10-06     1  2
1 2011-09-01     2  1
2 2011-11-05     3  3
3 2012-01-01     1  4
4 2012-01-01     2  4
5 2012-01-02     3  4

如果有人有更巧妙的解决方案,例如使用 groupby,我全神贯注。

更新: DSM 建议以下解决方案,这是我的方法的紧凑版本并且使用“密集”以 1 为增量进行排名:

dx['absmonth'] = dx['date'].str.split('-').str[:2].rank('dense')

【讨论】:

  • 嘿,你删除了我的推荐。 :-) 我们可能应该使用dense 而不是min 作为排名方法,即df["date"].str.split("-").str[:2].rank("dense") 来处理您注意到的情况。这样,它每次都会增加 1。
  • 哦,对不起,我以为你已经删除了,对不起!
  • 不久前我需要它,所以我added it。 :-)
【解决方案2】:

这个怎么样?

df['absmonth'] = df.date
dict = df.absmonth.unique()
dict.sort()
df.absmonth.replace(dict,range(1,len(dict)+1),inplace=True)

编辑如果您更喜欢使用日期而不是最后的格式:

df['absmonth'] = df.date.apply(lambda x: np.datetime64(x, 'M'))
dict = df.absmonth.unique()
dict.sort()
df.absmonth.replace(dict,range(1,len(dict)+1),inplace=True)
df.absmonth=df.absmonth.astype(int)

我认为应该存在一种避免使用 apply 的方法,但我没有找到。 Pandas.to_datetime(df['date'],format='%Y-%m-%d',unit='M') 对我不起作用。 不过,我希望它能完成你想要的。

【讨论】:

  • 您的解决方案无法精确工作,因为您按整个日期三元组 (Y, m, d) 排序并且不执行按对排序所需的解析 (Y,米)。做后者,我认为 groupby (或加入)可能是最好的。另请注意:在 pandas 14.0 和我提到的设置中,不幸的是,您编辑的解决方案不起作用:TypeError: cannot astype a datetimelike [datetime64[ns]] to [int32]。
  • 如果有帮助:在您的第一个提案的结果中,absmonth 列中的最后一个条目,即date = 2012-01-02 的行是5,它应该是4。
  • 好吧,我没意识到
  • 感谢您的 cmets;将来请提供您的建议结果,以便人们可以分析/确认:-)
  • ps:由于我之前找到了解决方案并对其进行了验证,并且 DSM 提供了改进,因此我将选择我的解决方案为“已接受”。再次感谢 cmets,考虑不同的想法总是好的。
猜你喜欢
  • 1970-01-01
  • 2016-06-24
  • 2019-10-10
  • 2020-03-30
  • 2019-10-25
  • 2020-09-29
  • 2019-05-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多