Python 为数据帧中的每个用户查找连续零的最长运行时间

Python 为数据帧中的每个用户查找连续零的最长运行时间,python,binary,counting,run-length-encoding,Python,Binary,Counting,Run Length Encoding,我希望找到一个数据帧中连续零的最大运行次数,结果按用户分组。我对在使用上运行RLE感兴趣 样本输入: 用户--日--用法 A---1----0 A---2----0 A---3----1 B---1----0 B---2----1 B---3----0 所需输出 用户-最长运行时间 a----2 b----1 mydata <- mydata[order(mydata$user, mydata$day),] user <- unique(mydata$user) d2 <- d

我希望找到一个数据帧中连续零的最大运行次数,结果按用户分组。我对在使用上运行RLE感兴趣

样本输入: 用户--日--用法
A---1----0
A---2----0
A---3----1
B---1----0
B---2----1
B---3----0

所需输出
用户-最长运行时间
a----2
b----1

mydata <- mydata[order(mydata$user, mydata$day),]
user <- unique(mydata$user)
d2 <- data.frame(matrix(NA, ncol = 2, nrow = length(user)))
names(d2) <- c("user", "longest_no_usage")
d2$user <- user
for (i in user) {
  if (0 %in% mydata$usage[mydata$user == i]) {
    run <- rle(mydata$usage[mydata$user == i]) #Run Length Encoding
    d2$longest_no_usage[d2$user == i] <- max(run$length[run$values == 0])
  } else {
    d2$longest_no_usage[d2$user == i] <- 0 #some users did not have no-usage days
  }
}
d2 <- d2[order(-d2$longest_no_usage),]

mydata我想下面就是您想要的,其中
continuous_zero
函数是顶部答案的一个改编

希望这有帮助

import pandas as pd
from itertools import groupby

df = pd.DataFrame([['A', 1], ['A', 0], ['A', 0], ['B', 0],['B',1],['C',2]], 
                  columns=["user", "usage"])

def len_iter(items):
    return sum(1 for _ in items)

def consecutive_zero(data):
    x = list((len_iter(run) for val, run in groupby(data) if val==0))
    if len(x)==0: return 0 
    else: return max(x)

df.groupby('user').apply(lambda x: consecutive_zero(x['usage']))
输出:

user
A    2
B    1
C    0
dtype: int64
使用by列
用户
用法
和helper
系列
首先用于连续值:

print (df)
  user  day  usage
0    A    1      0
1    A    2      0
2    A    3      1
3    B    1      0
4    B    2      1
5    B    3      0
6    C    1      1


df1 = (df.groupby([df['user'], 
                   df['usage'].rename('val'), 
                   df['usage'].ne(df['usage'].shift()).cumsum()])
        .size()
        .to_frame(name='longest_run'))

print (df1)
                longest_run
user val usage             
A    0   1                2
     1   2                1
B    0   3                1
         5                1
     1   4                1
C    1   6                1
然后仅过滤
0
行,获取
max
并添加附加非
0
组:

df2 = (df1.query('val == 0')
          .max(level=0)
          .reindex(df['user'].unique(), fill_value=0)
          .reset_index())
print (df2)
  user  longest_run
0    A            2
1    B            1
2    C            0
详细信息

print (df['usage'].ne(df['usage'].shift()).cumsum())
0    1
1    1
2    2
3    3
4    4
5    5
6    6
Name: usage, dtype: int32

如果您有一个大数据集,并且速度至关重要,那么您可能希望尝试使用高性能库

设置:

# pip install pyrle
# or 
# conda install -c bioconda pyrle
import numpy as np
np.random.seed(0)
import pandas as pd
from pyrle import Rle
size = int(1e7)
number = np.random.randint(2, size=size)
user = np.random.randint(5, size=size)
df = pd.DataFrame({"User": np.sort(user), "Number": number})
df
#          User  Number
# 0           0       0
# 1           0       1
# 2           0       1
# 3           0       0
# 4           0       1
# ...       ...     ...
# 9999995     4       1
# 9999996     4       1
# 9999997     4       0
# 9999998     4       0
# 9999999     4       1
# 
# [10000000 rows x 2 columns]
执行:

for u, udf in df.groupby("User"):
    r = Rle(udf.Number)
    is_0 = r.values == 0
    print("User", u, "Max", np.max(r.runs[is_0]))
# (Wall time: 1.41 s)


# User 0 Max 20
# User 1 Max 23
# User 2 Max 20
# User 3 Max 22
# User 4 Max 23

获取序列上的最大连续零数:

def max0(sr):
     return (sr != 0).cumsum().value_counts().max() - (0 if (sr != 0).cumsum().value_counts().idxmax()==0 else 1)


max0(pd.Series([1,0,0,0,0,2,3]))
四,


好极了,我从你在《SO》中无数的
pandas
答案中学到了很多东西,这一定是因为我非常接近同一个答案。唯一不同的是,我使用了
count()。重命名(…)
而不是
size()。到_frame(…)
后一种更好(我没有想到
reindex()
)。使用
.ne()
比使用
有什么好处吗=用于
cumsum()
?@AChampion-谢谢。前一段时间我曾经测试过
ne
vs
=
还有winner
.ne
,所以使用它(如果没有忘记的话),还有一些
()
应该被删除,所以代码更好
.count
是这里的另一个解决方案,我同意,但因为它计算非
NaN
值,我更喜欢
.size
,但在这里它似乎工作相同
.size
.count
谢谢!如果我想将groupby方法的输出转换成一个包含列user的数据帧,那么我将如何进行更改?您可以使用
aggregate
而不是
apply
,即
df=df.groupby('user').agg(lambda x:continuoused_zero(x['usage'])