将一列中的所有值与另一列中的所有值进行比较并返回索引

时间:2014-11-26 06:49:49

标签: numpy pandas compare

我感兴趣的是将1个dataframe列中的所有值与第2列中的所有值进行比较,然后生成列表或子集df,其值来自与第1列匹配的第3列的值。希望这个例子能更好地解释它:

有关简化示例,请说我生成以下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的任何值之内 列'mo​​d'并返回列'n'中与列'm'命中对应的值。因此,对于上面的代码,返回将是: 10.2,2.0,1.1 (因为101,201和501在'mod'栏中都有接近的命中率。)

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

3 个答案:

答案 0 :(得分:2)

我不会在熊猫中知道这种方法,但是当你将范围扩大到包括在内时 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]])

因为我们只关心&#39; mod&#39;具有相邻&#39; s的值,在轴上聚合= 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 <= mvals <= 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

答案 1 :(得分:1)

尝试以下方法:

# 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]

答案 2 :(得分:1)

我将制作numpy(导入为np),大熊猫在引擎盖下使用。 np.isclose返回一个布尔索引器:对于iterable的每个值,对应于值True的{​​{1}}或False值在每个值的m范围内atol

df["mod"]

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

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