Python 获取熊猫中的日期分位数

Python 获取熊猫中的日期分位数,python,numpy,pandas,Python,Numpy,Pandas,我有一些数据看起来像: user timestamp value1 a 2007-01-01 7 a 2007-02-02 8 a 2007-02-03 9 b 2007-02-04 1 a 2007-02-05 2 b 2007-02-06 3 b 2007-02-07 4 a 2007-02-08 5 ... las

我有一些数据看起来像:

user  timestamp  value1 
   a 2007-01-01       7 
   a 2007-02-02       8 
   a 2007-02-03       9 
   b 2007-02-04       1 
   a 2007-02-05       2 
   b 2007-02-06       3 
   b 2007-02-07       4 
   a 2007-02-08       5 
...
     last_entry median_entry first_entry
user                                    
a    2007-02-08   2007-02-03  2007-01-01
b    2007-02-07   2007-02-06  2007-02-04
其中每个用户有不同数量的条目

我的目标是了解这些条目的生成速度,并输出如下内容:

user  timestamp  value1 
   a 2007-01-01       7 
   a 2007-02-02       8 
   a 2007-02-03       9 
   b 2007-02-04       1 
   a 2007-02-05       2 
   b 2007-02-06       3 
   b 2007-02-07       4 
   a 2007-02-08       5 
...
     last_entry median_entry first_entry
user                                    
a    2007-02-08   2007-02-03  2007-01-01
b    2007-02-07   2007-02-06  2007-02-04
到目前为止,我有如下代码:

gb = df.groupby('user')
time_median = gb['timestamp'].median()
但这给了我
数据错误:没有要聚合的数字类型
,大概是因为日期不是数字


我想可以将日期转换为时间戳,找到这些时间戳的中间值,然后将它们转换回日期时间对象。这是最好的方法吗?

您可以使用
.searchsorted()
来计算每个用户的
max
min
之间的中间天数:

df = pd.DataFrame(data={'user': np.random.choice(['a', 'b','c'], size=100, replace=True), 'value': np.random.random(size=100), 'time_stamp': pd.date_range(start=date(2016, 1,1), freq='D', periods=100)})

df.groupby('user')['time_stamp'].describe()

user        
a     count                      28
      unique                     28
      top       2016-02-03 00:00:00
      freq                        1
      first     2016-01-01 00:00:00
      last      2016-04-05 00:00:00
b     count                      38
      unique                     38
      top       2016-03-24 00:00:00
      freq                        1
      first     2016-01-02 00:00:00
      last      2016-04-08 00:00:00
c     count                      34
      unique                     34
      top       2016-01-28 00:00:00
      freq                        1
      first     2016-01-03 00:00:00
      last      2016-04-09 00:00:00
中位数:

df.groupby('user')['time_stamp'].apply(lambda x: x.sort_values().iloc[x.searchsorted(x.min() + (x.max()-x.min())/2)])

dtype: object
user    
a     54   2016-02-24
b     50   2016-02-20
c     51   2016-02-21
dtype: datetime64[ns]

假设您希望将每个用户的初始日期之后的每个日期视为自该初始日期起的天数,您可以执行以下操作

import pandas as pd
dts =  pd.date_range(start="2015-01-15", periods=20)
users = ["a","b"]*10
df = pd.DataFrame({"user":users, "timestamp":dts})

date_info = df.groupby("user").agg({"timestamp":[min, max]})
date_info.columns = date_info.columns.droplevel()

since_incept = lambda x: x - x.min()
df["days"] = df.groupby("user").transform(since_incept)
df["days"] = df["days"].dt.days

median_td = lambda x: pd.Timedelta(pd.Series.median(x), "D")
med = df.groupby("user").agg({"days":[median_td]})

date_info["median"] = date_info["min"] + med.loc[:, ("days", "<lambda>")]
将熊猫作为pd导入
dts=pd.日期\范围(开始=“2015-01-15”,期间=20)
用户=[“a”,“b”]*10
df=pd.DataFrame({“user”:users,“timestamp”:dts})
date_info=df.groupby(“用户”).agg({“时间戳”:[min,max]})
date\u info.columns=date\u info.columns.droplevel()
因为_incept=lambda x:x-x.min()
df[“days”]=df.groupby(“用户”).transform(自接收以来)
df[“天”]=df[“天”].dt.days
中位数=λx:pd.Timedelta(pd.Series.median(x),“D”)
med=df.groupby(“用户”).agg({“天”:[median_td]})
日期信息[“中间值”]=日期信息[“最小值”]+med.loc[:,(“天”,“日”)]

不确定这是否正是您想要的,但您可以尝试使用
pd.TimeGrouper
并更改频率(
'20D'
'M'
等),以适应您的时间范围。以下是使用5个分位数(100天,20天组)的示例:

样本数据:

df = pd.DataFrame({'user': np.random.choice(['a', 'b','c'], size=100, replace=True),
                   'value': np.random.randint(10, size=100),
                   'time_stamp': pd.date_range(start=pd.datetime(2016, 1,1), freq='D', periods=100)})
df.head()

  time_stamp user  value
0 2016-01-01    b      3
1 2016-01-02    c      4
2 2016-01-03    a      8
3 2016-01-04    b      5
4 2016-01-05    c      5    
分位数生成:

quantiles = df.set_index('time_stamp').groupby([pd.TimeGrouper(freq='20D'), 'user'])['value'].sum()

time_stamp  user
2016-01-01  a       48
            b       22
            c       29
2016-01-21  a       28
            b       26
            c       25
2016-02-10  a       20
            b       57
            c       26
2016-03-01  a       25
            b       37
            c       35
2016-03-21  a       15
            b       37
            c       22
对于累积视图:

cum_quantiles = quantiles.groupby(level=[1]).cumsum()

time_stamp  user
2016-01-01  a        48
            b        22
            c        29
2016-01-21  a        76
            b        48
            c        54
2016-02-10  a        96
            b       105
            c        80
2016-03-01  a       121
            b       142
            c       115
2016-03-21  a       136
            b       179
            c       137
如果要以百分比形式查看值,请尝试添加百分比列:

totals = df.groupby('user')['value'].sum()
df['pct'] = df.apply(lambda x: x['value']/float(totals[x['user']]), axis=1)

然后重复上述步骤,将
'value'
更改为
'pct'

我的问题可能不清楚,但我找到了一个适合我的解决方案

def get_quantile(df, q):
    # Function that gets quantile from integer timestamp, then changes
    # back to a date_time object
    return pd.to_datetime(df['timestamp'].quantile(q, interpolation='nearest'))

df = pd.DataFrame(data={'user': np.random.choice(['a', 'b','c'], size=100, replace=True), 'value': np.random.random(size=100), 'date_time': pd.date_range(start=date(2016, 1,1), freq='D', periods=100)})

# Make a column of integer timestamps
df['timestamp'] = df['date_time'].astype('int')

editors = d.groupby('editor')

result = pd.DataFrame()
# Add columns of quantiles
result['first_quantile'] = get_quantile(editors, .25)
etc.
用我们自己的中值函数分组 设置您的列 定义我们自己的时间中值函数 设置聚合配置 总数的 结果 另一种更简单的中位数 如果您只想要完整的日期,也可以用这种方法计算错误的中间值:

def median_time(x):
    x = list(x)
    median_entry = (len(x) - 1) / 2.0
    x.sort()
    return x[round(median_entry)]

如果不需要精确的中位数,可以对日期进行排序并取近似的中间值(例如,偶数个元素的中位数将是元组对中的第一个数字,因此
1,2,2,4,4,6
的中位数将为2,因为(2,4)是中间元素)


对于分位数,这不重要,对吗?啊,是的,忽略它,因为它是无关的。不确定我在想什么
df.groupby('user').agg(agg_config)
     last_entry median_entry first_entry
user                                    
a    2007-02-08   2007-02-03  2007-01-01
b    2007-02-07   2007-02-06  2007-02-04
def median_time(x):
    x = list(x)
    median_entry = (len(x) - 1) / 2.0
    x.sort()
    return x[round(median_entry)]
>>> df.groupby('user').timestamp.agg({
        'first_entry': 'first', 
        'last_entry': 'last', 
        'median_entry': lambda group: sorted(group)[len(group) // 2]})

      last_entry first_entry median_entry
user                                     
a     2007-02-08  2007-01-01   2007-02-03
b     2007-02-07  2007-02-04   2007-02-06