我有一些类似的数据:
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()
但这给了我DataError: No numeric types to aggregate
,大概是因为日期不是数字。
我想可以将日期转换为时间戳,找到这些日期的中位数,然后将它们转回date_time对象。这是最好的方式吗?
答案 0 :(得分:2)
我可能在我的问题中不清楚,但我找到了一个适合我的解决方案。
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.
答案 1 :(得分:1)
您可以使用.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]
答案 2 :(得分:1)
假设您希望将每个用户的初始日期之后的每个日期视为自此初始日期以来的天数,您可以执行类似
的操作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>")]
答案 3 :(得分:1)
不确定这是否正是您所寻找的,但您可以尝试使用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'
答案 4 :(得分:1)
sapply(cn, function(x) rowSums(mydata[, paste0(x, 1:2)]))
df['first_entry'] = df['timestamp']
df['median_entry'] = df['timestamp']
df['last_entry'] = df['timestamp']
def median_time(x):
x = list(x)
median_entry = (len(x) - 1) / 2.0
x.sort()
if median_entry % 1 == 0:
return x[int(median_entry)]
else:
lower_date = x[int(median_entry)]
upper_date = x[int(median_entry) + 1]
return lower_date + (upper_date - lower_date) / 2.0
agg_config = {'first_entry': pd.np.min,
'median_entry': median_time,
'last_entry': pd.np.max}
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
答案 5 :(得分:1)
如果您不需要精确的中位数,您可以对日期进行排序并采用近似中间值(例如偶数个元素的中位数将是元组对中的第一个数字,因此1, 2, 2, 4, 4, 6
的中位数将是2因为(2,4)是中间元素。)
>>> 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