Pandas DataFrame:每个数据帧的不同列中按顺序的相同值的数量

2024-06-16 13:37:11 发布

您现在位置:Python中文网/ 问答频道 /正文

假设我在Python中有一个pandas数据框,它显示了不同单位的业务部门负责人的名字。可能看起来像这样

          Leader_Jan Leader_Feb Leader_Mar Leader_Apr
Unit1       Nina       Nina       Nina       Nina
Unit2       Lena       Lena        NaN       Lena
Unit3       Alex      Maria       Alex       Alex
Unit4     Emilia        NaN        NaN        NaN
Unit5        NaN    Corinna      Petra        NaN

可以像这样重新创建:

import pandas as pd
import numpy as np
a = ['Nina','Nina','Nina','Nina']
b = ['Lena','Lena',np.NaN,'Lena']
c = ['Alex','Maria','Alex','Alex']
d = ['Emilia',np.NaN,np.NaN,np.NaN]
e = [np.NaN,'Corinna','Petra',np.NaN]
data = pd.DataFrame(data=[a,b,c,d,e], columns =['Leader_Jan','Leader_Feb','Leader_Mar','Leader_Apr'], index=['Unit1','Unit2','Unit3','Unit4','Unit5'])

背景:我想了解哪些单位的领导在哪些单位停留的时间很短或很长(以月为单位),以便以后了解我公司的特定单位是否存在团队冲突。

我想在数据框中添加每个单位的最小值和最大值(以月为单位),即领导者在一个不间断期间在那里的时间。由于可能的中断(见第2单元和第3单元),我不能只对每行中的不同名称使用值\计数。我更需要找出由NaN值和其他名称分隔的不同领导者名称序列的长度。要查看我认为的序列,请检查此照片中的不同颜色:

sequences_colored

如你所见,第二单元和第三单元中的中断应该会导致多个停留时间。不应计算序列中的月份数。你知道吗

结果应该如下所示:

      Leader_Jan Leader_Feb Leader_Mar Leader_Apr  Min_length_of_stay_leaders  \
Unit1       Nina       Nina       Nina       Nina                           4   
Unit2       Lena       Lena        NaN       Lena                           1   
Unit3       Alex      Maria       Alex       Alex                           1   
Unit4     Emilia        NaN        NaN        NaN                           1   
Unit5        NaN    Corinna      Petra        NaN                           1   

       Max_length_of_stay_leaders  
Unit1                           4  
Unit2                           2  
Unit3                           2  
Unit4                           1  
Unit5                           1 

我知道这可能是相当复杂的后续,但我会喜欢任何类型的帮助/提示等,因为我有点迷失在这里。你知道吗


Tags: np单位nanjanfeb单元leaderalex
2条回答

实际上,使用itertools.groupby非常容易:

from itertools import groupby

def min_max_durations(row):
    # the group object consumes the iterator, but we don't care about the values 
    # so we just sum "1" to get the length.
    # Taken from https://stackoverflow.com/questions/44490079/how-to-turn-an-itertools-grouper-object-into-a-list
    durations = [sum(1 for _ in group) for key, group in groupby(row) if not isinstance(key, float)]
    return min(durations), max(durations)

data["min_lengths_of_stay"], data["max_lengths_of_stay"] = zip(*data.apply(min_max_durations, axis=1))

float的实例检查只是从计数中移除NaN值的一种快速方法,您可以将其任意复杂化。你知道吗

这将输出正确的结果(请注意,复制粘贴复制代码在Unit3中有3个“Alex”条目,与您的示例不同)

      Leader_Jan Leader_Feb Leader_Mar Leader_Apr  min_lengths_of_stay  \
Unit1       Nina       Nina       Nina       Nina                    4   
Unit2       Lena       Lena        NaN       Lena                    1   
Unit3      Maria       Alex       Alex       Alex                    1   
Unit4     Emilia        NaN        NaN        NaN                    1   
Unit5        NaN    Corinna      Petra        NaN                    1   
       max_lengths_of_stay  
Unit1                    4  
Unit2                    2  
Unit3                    3  
Unit4                    1  
Unit5                    1  

这会让你开始-

temp = df.apply(lambda x: x.groupby((x != x.shift()).cumsum()).cumcount()+1, axis=1)

mins = temp.min(1)
maxs = temp.max(1)
mask = temp.apply(lambda x: x.is_monotonic_increasing and x.is_unique, axis=1)
mins.loc[mask] = maxs.loc[mask]
mins.name='Min_length_of_stay_leaders'
maxs.name='Max_length_of_stay_leaders'

df.join(mins).join(maxs)

输出

      Leader_Jan Leader_Feb Leader_Mar Leader_Apr  Min_length_of_stay_leaders  \
Unit1       Nina       Nina       Nina       Nina                           4   
Unit2       Lena       Lena        NaN       Lena                           1   
Unit3       Alex      Maria       Alex       Alex                           1   
Unit4     Emilia        NaN        NaN        NaN                           1   
Unit5        NaN    Corinna      Petra        NaN                           1   

       Max_length_of_stay_leaders  
Unit1                           4  
Unit2                           2  
Unit3                           2  
Unit4                           1  
Unit5                           1 

解释

temp = df.apply(lambda x: x.groupby((x != x.shift()).cumsum()).cumcount()+1, axis=1)

这将为您提供按名称分组的连续领导者计数-

    Leader_Jan  Leader_Feb  Leader_Mar  Leader_Apr
Unit1   1   2   3   4
Unit2   1   2   1   1
Unit3   1   1   1   2
Unit4   1   1   1   1
Unit5   1   1   1   1

只需提取maxmin-

mins = temp.min(1)
maxs = temp.max(1)

问题就出现在Nina身上——她一直在工作,所以在这种情况下min也需要是4。你知道吗

因此,对于边的情况,mask对象检测严格单调递增的序列,如果是这样的话,则替换为max。你知道吗

我仍然不确定它是否适用于所有情况,所以请检查

相关问题 更多 >