【问题标题】:Manipulating Dictionary of Dataframes操作数据框字典
【发布时间】:2019-09-05 21:48:22
【问题描述】:

我有以下数据框:

Name1  Number1  Name2  Number2  Group
 R       1        G       5       1
 B       EXP      Y       9       2
 Y       225      L       185     2
 F       17       D       2       2
 H       259      G       175     3 
 X       172      Q       EXP     3

我正在尝试搜索每个“组”,并查看 either Number 列中的任何数字是否在特定范围内。如果此范围内的组中存在一个值,我想将组中的 ALL 名称附加到列表中。一个很大的障碍是 Number 列可以包含偶尔出现的字符串,并且这些列的处理方式与超出范围的数字相同。

在这个例子中,我们会说范围是 200-300

搜索组后的结果列表将是:

L = [B,Y,Y,L,F,D,H,G,X,Q]

请注意,列表中没有包含第 1 组的名称,因为第 1 组在指定范围内的 Number1/Number2 列中不包含任何值。

到目前为止我的代码:

newList = {}
dict_of_groups = {k: v for k, v in df.groupby('Group')}
for df in dict_of_groups.values()
    if df[df['Number1'] | df['Number2'] > 199]: #how do I specify AND < 300 here?
        a = df['Number1'].values.tolist()
        b = df['Number2'].values.tolist()
        newList.update(a,b)

我对如何有效地操作 dict_of_dataframes 中的每个数据帧有点困惑。有关如何最好地与这些团体合作的任何建议?

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    您的列中有一些无效值,必须将其转换为有效数值才能执行有效比较。这里有几个选项,您可以只使用pandas 操作,并执行较慢的groupby,或者您可以下拉到numpy 以获得非常有效的解决方案。

    选项 1
    stack + unstack + groupby + transform


    names = df.filter(like='Name').to_numpy()
    
    m = (pd.to_numeric(df.filter(like='Number').stack(), errors='coerce')
          .between(200, 300).unstack())
    
    mask = m.groupby(df['Group']).transform('any').any(1)
    
    names[mask].ravel().tolist()
    

    ['B', 'Y', 'Y', 'L', 'F', 'D', 'H', 'G', 'X', 'Q']
    

    选项 2
    使用np.add.at 和一些掩蔽的更快的numpy 解决方案

    a = df.filter(like='Name').to_numpy().ravel()
    b = df.filter(like='Number').to_numpy().ravel()
    c = np.repeat(df['Group'].to_numpy(), a.shape[0] // df.shape[0])
    n = pd.to_numeric(b, errors='coerce')
    
    
    f = np.zeros(c.max()+1, dtype=int)
    m = np.logical_and(n >= 200, n <= 300)
    np.add.at(f, c, m)
    
    mask = f[c].astype(bool)
    
    a[mask]
    

    array(['B', 'Y', 'Y', 'L', 'F', 'D', 'H', 'G', 'X', 'Q'], dtype=object)
    

    时间

    df = pd.concat([df]*1000, ignore_index=True)
    
    %timeit chris_stack()
    22.7 ms ± 1.86 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    
    %timeit chris_numpy()
    11.9 ms ± 153 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\
    
    %timeit quang()
    16.7 ms ± 101 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    
    %timeit jezrael()
    78.5 ms ± 685 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
    

    【讨论】:

      【解决方案2】:

      使用wide_to_long 进行整形,然后使用GroupBy.anyGroupBy.transform 对每个组进行测试,因此可能的过滤列Name

      df = pd.wide_to_long(df.reset_index(),['Name','Number'],i=['index','Group'],j='drop')
      
      s = pd.to_numeric(df['Number'], errors='coerce').between(200, 300)
      
      L = df.loc[s.groupby(level=1).transform('any'), 'Name'].tolist()
      print (L)
      ['B', 'Y', 'Y', 'L', 'F', 'D', 'H', 'G', 'X', 'Q']
      

      详情

      print (df)
                       Name Number
      index Group drop            
      0     1     1       R      1
                  2       G      5
      1     2     1       B    EXP
                  2       Y      9
      2     2     1       Y    225
                  2       L    185
      3     2     1       F     17
                  2       D      2
      4     3     1       H    259
                  2       G    175
      5     3     1       X    172
                  2       Q    EXP
      

      【讨论】:

        【解决方案3】:

        类似于 Chris 的回答,但没有 stack/unstack

        s1 = pd.to_numeric(df['Number1'], errors='coerce')
        s2 = pd.to_numeric(df['Number2'], errors='coerce')
        
        s = s1.between(200,300) | s2.between(200,300)
        
        df.loc[s.groupby(df['Group']).transform('any'), ['Name1', 'Name2']].values.ravel()
        

        给予:

        array(['B', 'Y', 'Y', 'L', 'F', 'D', 'H', 'G', 'X', 'Q'], dtype=object)
        

        注意:如果您有超过 2 个名称/数字列,您可以考虑将数据框转换为长格式。

        【讨论】:

        • 我有点困惑,你如何“使用”数组对象。我正在尝试获取列表中的值。
        • @MaxB 您可以随时通过list(array_object) 获取列表。只是好奇,您想如何“使用”您的列表?
        • @QuangHoang 啊,我明白了,很抱歉造成混乱。我还有另一个列表,我将与此列表进行比较,以了解本质上的差异。
        • 在这种情况下,您几乎肯定想查看set,除非这两个列表的长度相同并且您想逐个元素地比较它们。
        • @QuangHoang 是的,我知道,忘了把它放在问题中,但不想改变它并混淆人们。 :P
        猜你喜欢
        • 1970-01-01
        • 2017-11-17
        • 2021-11-30
        • 1970-01-01
        • 1970-01-01
        • 2023-01-13
        • 1970-01-01
        • 2020-10-01
        • 2017-11-30
        相关资源
        最近更新 更多