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