Python 在dataframe中查找与当前行值不同的值的先前连续出现次数

Python 在dataframe中查找与当前行值不同的值的先前连续出现次数,python,pandas,dataframe,Python,Pandas,Dataframe,假设我们有以下数据帧: df = pd.DataFrame({'x':[0,0,1,0,0,0,0],'y':[1,1,1,1,1,1,0],'z':[0,1,1,1,0,0,1]}) x y z 0 0 1 0 1 0 1 1 2 1 1 1 3 0 1 1 4 0 1 0 5 0 1 0 6 0 0 1 所有数据帧都由1或0填充。分别查看每一列,如果当前行值不同于前一个值,我需要计算前一个连续值的数量: x y z 0

假设我们有以下数据帧:

df = pd.DataFrame({'x':[0,0,1,0,0,0,0],'y':[1,1,1,1,1,1,0],'z':[0,1,1,1,0,0,1]})

   x  y  z
0  0  1  0
1  0  1  1
2  1  1  1
3  0  1  1
4  0  1  0
5  0  1  0
6  0  0  1
所有数据帧都由1或0填充。分别查看每一列,如果当前行值不同于前一个值,我需要计算前一个连续值的数量:

   x  y  z
0        
1        1
2  2     
3  1     
4        3
5        
6     6  2

我试图编写一个lambda函数并将其应用于整个数据帧,但失败了。有什么想法吗?

您可以尝试以下方法,首先确定“运行”并获得“运行”长度。您将只在它切换的位置输入,因此它是除最后一个外的所有运行的长度

import pandas as pd
import numpy as np

def func(x,missing=np.NaN):
        runs = np.cumsum(np.append(0,np.diff(x)!=0))
        switches = np.where(np.diff(x!=0))[0] + 1
        out = np.repeat(missing,len(x))
        out[switches] = np.bincount(runs)[:-1]
        # thanks to Scott see comments below 
        ##out[switches] = pd.value_counts(runs,sort=False)[:-1]
        return(out)

df.apply(func)

    x   y   z
0   NaN NaN NaN
1   NaN NaN 1.0
2   2.0 NaN NaN
3   1.0 NaN NaN
4   NaN NaN 3.0
5   NaN NaN NaN
6   NaN 6.0 2.0
运行长度编码的良好实现可能会更快。。但是我不太熟悉python中的它。

让我们试试这个:

def f(col):
    x = (col != col.shift().bfill())
    s = x.cumsum()
    return s.groupby(s).transform('count').shift().where(x)

df.apply(f).fillna('')
输出:

   x  y  z
0         
1        1
2  2      
3  1      
4        3
5         
6     6  2
详细信息:

使用
apply
,在数据帧的每列上应用自定义函数。
在列中找到差异点,然后使用
cumsum
创建连续值组,然后使用
groupby
transform
为每条记录创建一个
count
,然后使用
where
为差异点屏蔽列中的值。

以及填充数据框其余部分的内容?当前值与上一个值相同时,输出数据框缺少值。因此,第一行也缺少值。为什么要使用0和1而不是实际的布尔值?一般来说,这个问题可以扩展到在dataframe中只允许0或1个以上的值。我认为仅限于布尔值可以提供更快的实现,但我不想将解决方案仅限于二进制值。为了获得更好的性能,您可以将
out[switches]=pd.value\u计数(runs,sort=False)[:-1]
和使用
out[switches]=np.bincount(runs)[:-1]
。我很惊讶您的解决方案比ScottBoston的解决方案快近3倍,而ScottBoston的解决方案在另一边似乎更紧凑。@lpj是的,使用numpy进行计算总是比使用pandas快。熊猫使用大量的numpy和额外的食物。如果您可以只使用numpy编写逻辑,那么它将始终运行得更快。因此,我建议将我们的pd.value_计数更改为np.bincount。我对熊猫的了解要比努比多。我在这里从伟大的numpy答案中学习。嗨,斯科特,谢谢你的伟大建议。是的,在本例中,np.bincount工作得很好,我将在答案中包括它。可爱的熊猫代码顺便说一句。你好@StupidWolf。你的代码很棒。没问题。请随意使用该代码。非常好的结果和解释。我很好奇是否存在另一种基于将函数应用于行而不是列的解决方案:
df.apply(function,axis=1)
。预期的结果完全相同。使用apply(axis=1)在pandas中是一个相当大的“否”。使用该语句,您将逐行进行迭代,这违背了将过程矢量化的目的。大多数情况下,你可以找到一种不必一行一行走的方法。axis=1时应用是最慢的操作之一。