熊猫:联合重复的字符串

时间:2017-01-13 11:28:57

标签: python pandas

我有数据框

ID     url     date   active_seconds
111    vk.com   12.01.2016   5
111    facebook.com   12.01.2016   4
111    facebook.com   12.01.2016   3
111    twitter.com    12.01.2016    12
222    vk.com      12.01.2016   8
222    twitter.com    12.01.2016   34
111    facebook.com   12.01.2016   5

我需要得到

ID     url     date   active_seconds
111    vk.com   12.01.2016   5
111    facebook.com   12.01.2016   7
111    twitter.com    12.01.2016    12
222    vk.com      12.01.2016   8
222    twitter.com    12.01.2016   34
111    facebook.com   12.01.2016   5

如果我尝试

df.groupby(['ID', 'url'])['active_seconds'].sum()

它将所有字符串联合起来。我该怎么做才能得到满足感?

3 个答案:

答案 0 :(得分:3)

解决方案1 ​​ - 仅cumsumurl

您需要groupbycumsum布尔掩码创建的自定义Series,但是url列需要first url。然后使用aggregate删除级别g = (df.url != df.url.shift()).cumsum() print (g) 0 1 1 2 2 2 3 3 4 4 5 5 6 6 Name: url, dtype: int32 g = (df.url != df.url.shift()).cumsum() #another solution with ne #g = df.url.ne(df.url.shift()).cumsum() print (df.groupby([df.ID,df.date,g], sort=False).agg({'active_seconds':'sum', 'url':'first'}) .reset_index(level='url', drop=True) .reset_index() .reindex(columns=df.columns)) ID url date active_seconds 0 111 vk.com 12.01.2016 5 1 111 facebook.com 12.01.2016 7 2 111 twitter.com 12.01.2016 12 3 222 vk.com 12.01.2016 8 4 222 twitter.com 12.01.2016 34 5 111 facebook.com 12.01.2016 5 ,并按reset_index删除最后一次重新排序列:

g = (df.url != df.url.shift()).cumsum().rename('tmp')
print (g)
0    1
1    2
2    2
3    3
4    4
5    5
6    6
Name: tmp, dtype: int32

print (df.groupby([df.ID, df.url, df.date, g], sort=False)['active_seconds']
         .sum()
         .reset_index(level='tmp', drop=True)
         .reset_index())

    ID           url        date  active_seconds
0  111        vk.com  12.01.2016               5
1  111  facebook.com  12.01.2016               7
2  111   twitter.com  12.01.2016              12
3  222        vk.com  12.01.2016               8
4  222   twitter.com  12.01.2016              34
5  111  facebook.com  12.01.2016               5
cumsum

解决方案2 - IDurlg = df[['ID','url']].ne(df[['ID','url']].shift()).cumsum() print (g) ID url 0 1 1 1 1 2 2 1 2 3 1 3 4 2 4 5 2 5 6 3 6 print (df.groupby([g.ID, df.date, g.url], sort=False) .agg({'active_seconds':'sum', 'url':'first'}) .reset_index(level='url', drop=True) .reset_index() .reindex(columns=df.columns)) ID url date active_seconds 0 1 vk.com 12.01.2016 5 1 1 facebook.com 12.01.2016 7 2 1 twitter.com 12.01.2016 12 3 2 vk.com 12.01.2016 8 4 2 twitter.com 12.01.2016 34 5 3 facebook.com 12.01.2016 5

df.url

添加列rename的解决方案,但是helper df中的必要g = df[['ID','url']].ne(df[['ID','url']].shift()).cumsum() g.columns = g.columns + '1' print (g) ID1 url1 0 1 1 1 1 2 2 1 2 3 1 3 4 2 4 5 2 5 6 3 6 print (df.groupby([df.ID, df.url, df.date, g.ID1, g.url1], sort=False)['active_seconds'] .sum() .reset_index(level=['ID1','url1'], drop=True) .reset_index()) ID url date active_seconds 0 111 vk.com 12.01.2016 5 1 111 facebook.com 12.01.2016 7 2 111 twitter.com 12.01.2016 12 3 222 vk.com 12.01.2016 8 4 222 twitter.com 12.01.2016 34 5 111 facebook.com 12.01.2016 5 列:

pivot_table

<强>计时

类似的解决方案,但groupbyIn [180]: %timeit (df.assign(g=df.ID.ne(df.ID.shift()).cumsum()).pivot_table('active_seconds', ['g', 'ID', 'url', 'date'], None, 'sum').reset_index([1, 2, 3]).reset_index(drop=True)) 100 loops, best of 3: 5.02 ms per loop In [181]: %timeit (df.groupby([df.ID, df.url, df.date, (df.url != df.url.shift()).cumsum().rename('tmp')], sort=False)['active_seconds'].sum().reset_index(level='tmp', drop=True).reset_index()) 100 loops, best of 3: 3.62 ms per loop 更慢:

RUNJAVA com.hyperion.calcmgr.common.cdf.MaxLScriptFunction
"-D"
"123456.1234567" /* Private key */ 
""
"login $key 944589711255867592121610891 $key 944589711255867592121610891 on 'localhost'"
"alter database 'MIS'.'Analytic'
clear data in region
'{
.....
} ' physical "
"logout"
"spool off"
"exit";

答案 1 :(得分:3)

  • (s != s.shift()).cumsum()是识别连续标识符组的典型方法
  • pd.DataFrame.assign是一种将新列添加到数据框副本并链接更多方法的便捷方法
  • pivot_table允许我们重新配置我们的表格并汇总
  • args - 这是我的样式偏好,以保持代码更清晰。我会通过pivot_table
  • 将这些参数传递给*args
  • reset_index * 2清理并获得最终结果
args = ('active_seconds', ['g', 'ID', 'url', 'date'], None, 'sum')
df.assign(g=df.ID.ne(df.ID.shift()).cumsum()).pivot_table(*args) \
    .reset_index([1, 2, 3]).reset_index(drop=True)

    ID           url        date  active_seconds
0  111  facebook.com  12.01.2016               7
1  111   twitter.com  12.01.2016              12
2  111        vk.com  12.01.2016               5
3  222   twitter.com  12.01.2016              34
4  222        vk.com  12.01.2016               8
5  111  facebook.com  12.01.2016               5

答案 2 :(得分:2)

看起来你想要一个cumsum()

In [195]: df.groupby(['ID', 'url'])['active_seconds'].cumsum()
Out[195]:
0     5
1     4
2     7
3    12
4     8
5    34
6    12
Name: active_seconds, dtype: int64