【问题标题】:Find out middle occurrence of "0" and first occurrence ''1" of an event in pandas dataframe找出熊猫数据框中事件的中间出现“0”和第一次出现“1”
【发布时间】:2018-02-26 16:28:36
【问题描述】:

您好,我有一个 pandas 数据框,其中包含事件列和其他列。我想在 id 上执行 group by 在那个 group by 我想从所有连续 0 中取出 2 条记录 我想找出连续 5 0 的模式可能更多,但它必须始终跟在 1 之后然后识别记录集,即继续 5 个 0,然后是下一个 1,然后获取中间行(这 5 个 0 中的 0)记录,并找出那些 0 之后的第一个 1 并取该行。但是对于 0s aleast,我应该重复 5 次或更多,然后从最后 5 次中取出中间行。

简而言之: 我想要 0 和 1 的集合,条件是只取 1,上面你发现连续 5 个 0 或更多,如果这种模式是多次的,那么采用一个模式为每个具有 0 和 1 的 id 获取两条记录

例如。

 import pandas as pd
 data={'id':[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
        2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2],
  'name': ['a','b','c','d','e','f','g','h','i','j','k','l','m','n'
          ,'o','p','q','r','s','t','a1','b1','c1','d1','e1','f1','g1','h1','i1','j1','k1','l1','m1','n1'
          ,'o1','p1','q1','r1','s1','t1','aa','bb','cc','dd','ee','ff',
          'gg','hh','ii','jj','kk','ll','mm','nn'
          ,'oo','pp','qq','rr','ss','tt','aa1','bb1','cc1','dd1','ee1','ff1',
          'gg1','hh1','ii1','jj1','kk1','ll1','mm1','nn1'
          ,'oo1','pp1','qq1','rr1','ss1','tt1'],
  'value':[0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
           0,0,0,0,0,0,0,1,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0]}
 df=pd.DataFrame.from_dict(data)

作为输出,我想为每个 id 获取 2 条记录,一条用于 0,一条用于 1。并且0行应该是5个或更多连续0的中间记录。

预期的输出是:

    id  name    value

 16 1   q       0
 19 1   t       1

64  2   ee1     0
67  2   hh1     1

【问题讨论】:

  • 如果您的问题解决了,请用绿色勾号标记正确答案,以便关闭线程。

标签: python pandas dataframe


【解决方案1】:

您可以使用数据透视表并为不同的值应用掩码。首先我们应该按idvalue 对分组:

df_grouped = df.reset_index().pivot_table(index=['id','value'],
                                          values='name',
                                          aggfunc=lambda x: ','.join(x)
                                          ).reset_index()


df_grouped['name'] = df_grouped['name'].str.split(',')

print(df_grouped)

   id  value             name
0   1      0  a,b,d,e,f,g,h,i
1   1      1              c,j
2   2      0        l,m,n,o,p
3   2      1    k,q,r,s,t,u,w

然后选择每个value==0id 对的零并保留中间值:

mask_zeros = ((df_grouped['value']==0)*
              (df_grouped['name'].apply(len)>=5))
df_zeros = mask_zeros*df_grouped['name'].apply(
           lambda x: x[int(np.ceil(.5*len(x)))] 
                      if len(x)%2==1 
                      else x[int(.5*len(x))])
print(df_zeros)

0    f
1     
2    o
3     

然后根据value==1id 对选择名字:

mask_ones = (df_grouped['value']==1)
df_ones = mask_ones*df_grouped['name'].apply(
           lambda x: x[0] if len(x)>0 else None)

print(df_ones)

0     
1    c
2     
3    k

然后通过分配仅保留选定的名称:

 df_grouped['name'] = df_ones + df_zeros

 df_grouped = df_grouped.merge(df.reset_index(),
                               on=['name','value','id']
                               ).set_index('index')
 print(df_grouped)

       id  value name
index                
5       1      0    f
2       1      1    c
14      2      0    o
10      2      1    k

【讨论】:

  • 感谢 Mabel,但我只需要 4 条记录作为输出,仅此而已。我不明白你的回答对我有什么帮助?
  • 好的,我知道了。如果有奇数个 0 以及与中间相邻的两个和第一个 1,你想返回中间元素吗?
  • 是的,我不需要两个相邻的小改动,因为 0 只有一个就可以了。
【解决方案2】:

我分解步骤

df['New']=df.value.diff().fillna(0).ne(0).cumsum()
df1=df.loc[df.value.eq(0)]
s1=df1.groupby(['id','New']).filter(lambda x : len(x)>=5 ).groupby('id').apply(lambda x : x.iloc[len(x)//2-1:len(x)//2+1] if len(x)%2==0 else x.iloc[[(len(x)+1)//2],:] ).reset_index(level=0,drop=True)
s2=df1.groupby(['id','New']).filter(lambda x : len(x)>=5 )
pd.concat([df.loc[s2.drop_duplicates(['id'],keep='last').index+1],s1]).sort_index()
Out[1995]: 
    id name  value  New
5    1    f      0    2
6    1    g      0    2
9    1    j      1    3
14   2    o      0    4
16   2    q      1    5

【讨论】:

  • 实际上似乎我没有涵盖我的数据集的所有场景.. 我不是在寻找下一个立即数,即 index+1,但我正在寻找在 0 之后出现的 1,现在 1 可以是下一个直接索引,或者它可以在几个 0 之后。所以我需要我们确定的 0 之后的任何第一个 1 吗?对此有何建议?
  • 你的另一个问题是,在我的数据集中,它的发生就像我得到很多不一样。 0 的数量就像 20 -25 在计数方面然后得到 1 那么是否有可能获得最后 5 个连续 0 并将其中间作为 0 的一个记录并将下一个即将到来的 1 作为 1 的另一个记录?我的数据是每个月的事件,所以在目前的情况下,我从 2014 年得到 0,从 2017 年得到 1,这是相当大的时间窗口..我希望我有点清楚?
猜你喜欢
  • 2017-05-06
  • 2022-06-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-23
  • 1970-01-01
  • 2017-01-19
  • 2019-05-13
相关资源
最近更新 更多