【问题标题】:Compare all values in one column with all values in another column and return indexes将一列中的所有值与另一列中的所有值进行比较并返回索引
【发布时间】:2014-11-26 06:49:49
【问题描述】:

我有兴趣将 1 个数据框列中的所有值与第 2 列中的所有值进行比较,然后使用与第 1 列匹配项相邻的第 3 列中的值生成列表或子集 df。希望这个例子能更好地解释它:

举个简单的例子,假设我生成了以下 pandas 数据框:

fake_df=pd.DataFrame({'m':[100,120,101,200,201,501,350,420,525,500],
                  'n':[10.0,11.0,10.2,1.0,2.0,1.1,3.0,1.0,2.0,1.0],
                  'mod':[101.001,121.001,102.001,201.001,202.001,502.001,351.001,421.001,526.001,501.001]})
print fake_df

我感兴趣的是在“m”列中找到所有值在 0.1 范围内的任何值 列“mod”并返回与列“m”命中相对应的列“n”中的值。所以对于上面的代码,返回将是: 10.2、2.0、1.1 (因为 101,201 和 501 在“mod”列中都有接近命中)。

我找到了比较同一行的方法,但不像上面那样。有没有办法在没有大量循环的熊猫中做到这一点? 谢谢!

【问题讨论】:

    标签: numpy pandas compare


    【解决方案1】:

    我不知道 pandas 中的这种方法,但是当您将范围扩大到包括 numpy,我想到了两个选项。

    简单/昂贵的方法

    如果你能忍受 N**2 的内存开销,你可以做 numpy 广播到 一步找出所有“相邻”元素:

    In [25]: fake_df=pd.DataFrame({'m':[100,120,101,200,201,501,350,420,525,500],
                      'n':[10.0,11.0,10.2,1.0,2.0,1.1,3.0,1.0,2.0,1.0],
                      'mod':[101.001,121.001,102.001,201.001,202.001,502.001,351.001,421.001,526.001,501.001]})
    
    In [26]: mvals = fake_df['m'].values
    
    In [27]: modvals = fake_df['mod'].values
    
    In [28]: is_close = np.abs(mvals - modvals[:, np.newaxis]) <= 0.1; is_close.astype(int)
    Out[28]: 
    array([[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, 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, 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, 0, 0, 0]])
    

    由于我们只关心具有相邻 'm' 的 'mod' 值,因此在 axis=0 上进行聚合:

    In [29]: is_close.any(axis=0).astype(int)
    Out[29]: array([0, 0, 1, 0, 1, 1, 0, 0, 0, 0])
    

    否则

    In [30]: fake_df.ix[is_close.any(axis=0), 'n']
    Out[30]: 
    2    10.2
    4     2.0
    5     1.1
    Name: n, dtype: float64
    

    高效/复杂的方法

    在小于 O(N**2) 的时间内找到相邻元素,无需任何散列/舍入 技巧,你必须做一些排序:

    In [103]: modvals_sorted = np.sort(modvals)
    
    In [104]: next_indices = np.searchsorted(modvals_sorted, mvals)
    

    您有下一个元素的索引,但它们可能指向原始元素之外 数组,所以最后需要一个额外的NaN 以避免IndexError。相同的 逻辑适用于 next_indices - 1 的先前元素:以避免 在第一个元素之前进行索引,我们也必须在前面加上一个 NaN。注意+ 1 的出现是因为NaN 之一已添加到开头。

    In [105]: modvals_sorted_plus = np.r_[np.nan, modvals_sorted, np.nan]
    
    In [106]: nexts = modvals_sorted_plus[next_indices + 1]
    
    In [107]: prevs = modvals_sorted_plus[(next_indices - 1) + 1]
    

    现在它是微不足道的。注意我们已经有了prevs &lt;= mvals &lt;= nexts,所以我们 不需要使用np.abs。此外,所有缺少的元素都是NaN,并且与它们进行比较会得到False,这不会改变any 操作的结果。

    In [108]: adjacent = np.c_[prevs, mvals, nexts]; adjacent
    Out[108]: 
    array([[     nan,  100.   ,  101.001],
           [ 102.001,  120.   ,  121.001],
           [     nan,  101.   ,  101.001],
           [ 121.001,  200.   ,  201.001],
           [ 121.001,  201.   ,  201.001],
           [ 421.001,  501.   ,  501.001],
           [ 202.001,  350.   ,  351.001],
           [ 351.001,  420.   ,  421.001],
           [ 502.001,  525.   ,  526.001],
           [ 421.001,  500.   ,  501.001]])
    
    In [109]: (np.diff(adjacent, axis=1) <= 0.1).any(axis=1)
    Out[109]: array([False, False,  True, False,  True,  True, False, False, False, False], dtype=bool)
    
    In [110]: mask = (np.diff(adjacent, axis=1) <= 0.1).any(axis=1)
    
    In [112]: fake_df.ix[mask, 'n']
    Out[112]: 
    2    10.2
    4     2.0
    5     1.1
    Name: n, dtype: float64
    

    【讨论】:

      【解决方案2】:

      尝试以下方法:

      # I assume all arrays involved to be or to be converted to numpy arrays
      import numpy as np
      m = np.array([100,120,101,200,201,501,350,420,525,500])
      n = np.array([10.0,11.0,10.2,1.0,2.0,1.1,3.0,1.0,2.0,1.0])
      mod = np.array([101.001,121.001,102.001,201.001,202.001,502.001,351.001,421.001,526.001,501.001])
      
      res = []
      # for each entry in mod, look in m for "close" values
      for i in range(len(mod)):
          # for each hit, store entry from n in result list
          res.extend(n[np.fabs(mod[i]-m)<=0.1])
      # cast result to numpy array
      res = np.array(res)
      print res
      

      输出是

      [ 10.2   2.    1.1]
      

      【讨论】:

        【解决方案3】:

        我将制作 pandas 在后台使用的 numpy(作为 np 导入)。 np.isclose 返回一个布尔索引器:对于可迭代的每个值,有一个 TrueFalse 值对应于 m 的值,位于 df["mod"] 的每个值的 atol 内。

        >>> for i, m in df["m"].iteritems():
        ...     indices = np.isclose(m, df["mod"], atol=0.1)
        ...     if any(indices):
        ...         print df["n"][i]
        

        使用您提供的 DataFrame 产生输出:

        10.2
        2.0
        1.1
        

        【讨论】:

        • 这并不能回答问题,因为您在mmod 之间的比较只比较了m[i]mod[i]。该问题要求对range(len(m)) 中的所有irange(len(mod)) 中的j 进行m[i]mod[j] 的比较。
        • 是的,感谢您指出这一点。编辑以便我回答问题,但看起来@immerrr 有路要走:)
        猜你喜欢
        • 1970-01-01
        • 2019-09-11
        • 1970-01-01
        • 2015-07-23
        • 2020-04-26
        • 1970-01-01
        • 2017-05-01
        • 2022-08-05
        • 2019-04-01
        相关资源
        最近更新 更多