【问题标题】:How to pick a subset of values with const difference from a list of values?如何从值列表中选择具有 const 差异的值子集?
【发布时间】:2021-03-03 16:25:11
【问题描述】:

我有一个包含值列表的数据框:

In [24]: data
Out[24]: 
[{'value': 1.2},
 {'value': 2.2},
 {'value': 1.8},
 {'value': 2.0},
 {'value': 1.1},
 {'value': 3.9},
 {'value': 0.0},
 {'value': 1.5},
 {'value': 2.5},
 {'value': 1.6},
 {'value': 2.3},
 {'value': 3.0},
 {'value': 3.3},
 {'value': 0.5},
 {'value': 4.0},
 {'value': 3.4},
 {'value': 0.8},
 {'value': 2.5},
 {'value': 2.1},
 {'value': 3.0}]

In [25]: df = pd.DataFrame(data=data)
In [26]: df
Out[26]: 
    value
0     1.2
1     2.2
2     1.8
3     2.0
4     1.1
5     3.9
6     0.0
7     1.5
8     2.5
9     1.6
10    2.3
11    3.0
12    3.3
13    0.5
14    4.0
15    3.4
16    0.8
17    2.5
18    2.1
19    3.0

现在我想通过以下方式选择这个数据框的一个子集:

  1. 选择最大值 - 很简单 - df['value'].max()
  2. 查找下 N 行,其值最接近最后一个值 - 0.2

即- 最大值是 4.0,所以我想找到值最接近4.0 - 0.2 = 3.8 的行,即第 5 行。 接下来,我想找到一个值为4.0 - (0.2 * 2) = 3.6的行,所以这将是第15行(3.4),依此类推(最多N次)

有没有快速的方法来做到这一点?

预期输出:

value  
0 4.0
1 3.9
2 3.4

我将使用的实际数据应该分布得更均匀,因此在每个预期值周围(即 3.8、3.6、3.4 左右)都会有许多接近值(例如 3.44、3.38、3.41)

【问题讨论】:

  • 所以您的预期输出应该只有 3 个值?
  • 值的个数是 N - 我想控制它
  • @CIsForCookies 考虑到接近4.0 - (0.2 * 3) = 3.4的值,我猜结果应该是3.4,对吗?
  • @ShubhamSharma 正确

标签: python pandas


【解决方案1】:

假设分辨率(0.2)预计比最接近的距离大很多,相信你可以使用merge_asof

step, N = 0.2, 3

maxval = df['value'].max()

(pd.merge_asof(df.sort_values('value'),
                      pd.DataFrame({'ref':maxval-np.arange(N)*step}).sort_values('ref'),
                      left_on='value',
                      right_on='ref',
                      direction='nearest')
   .assign(dist=lambda x: x['ref'].sub(x['value']).abs())
   .sort_values('dist')
   .drop_duplicates('ref')
)

输出:

    value  ref  dist
19    4.0  4.0   0.0
18    3.9  3.8   0.1
17    3.4  3.6   0.2

【讨论】:

  • 太棒了! :) 很抱歉没有更清楚,但你得到了我所需要的。我刚刚添加了一个 sort + dropna(以防 N 太大),就是这样
  • 不会有任何NaNmerge_asof,除非您的数据有它们。
  • @ClsForCookies 我的解决方案和 Shubham 的解决方案略有不同。我的不会像 Shubham 那样给出重复的值,而只能在假设的情况下工作。例如,它不适用于示例数据和N=4...
  • 这很好 - 在真实数据中假设成立
【解决方案2】:

根据我的理解,您可能想要:

arr = df['value'].max() - (0.2 * np.arange(1,len(df)+1))
out = (pd.merge_asof(pd.Series(arr,name='Derived_value').sort_values(),
   df['value'].sort_values(),left_on='Derived_value',right_on='value'))

除非您想完全按照计算值进行排序,否则上述方法应该可以:

out_one = (out.assign(Derived_value=pd.Categorical(out['Derived_value'],
        categories=arr,ordered=True)).sort_values("Derived_value"))

print(out_one)

   Derived_value  value
19           3.8    3.4
18           3.6    3.4
17           3.4    3.4
16           3.2    3.0
15           3.0    3.0
14           2.8    2.5
13           2.6    2.5
12           2.4    2.3
11           2.2    2.2
10           2.0    2.0
9            1.8    1.6
8            1.6    1.5
7            1.4    1.2
6            1.2    1.1
5            1.0    0.8
4            0.8    0.5
3            0.6    0.5
2            0.4    0.0
1            0.2    0.0
0            0.0    0.0

print(arr)
[3.8 3.6 3.4 3.2 3.  2.8 2.6 2.4 2.2 2.  1.8 1.6 1.4 1.2 1.  0.8 0.6 0.4
 0.2 0. ]

【讨论】:

  • 嗯,我也在考虑merge_asof。但我认为 OP 想要别的东西,arr 将是 maxval-np.arange(N)*step
  • @QuangHoang 你的确实更接近(添加dropna() 以防N 太大),但我很难解释到底是什么
  • @CIsForCookies 最好有更好的解释:)
  • @anky 我知道 :( 我还在想如何以一种简洁易懂的方式来表达...
【解决方案3】:

这是使用 numpy 广播的一种方法:

N = 5
v = df['value'].max() - np.arange(N) * 0.2
dist = np.abs(v[:, None] - df['value'].values)

df['value'].iloc[np.argmin(dist, axis=1)]

14    4.0
5     3.9
15    3.4
15    3.4
12    3.3
Name: value, dtype: float64

【讨论】:

  • 是的!当N 相对较小时,这更简单。但是遭受重复值的困扰......
猜你喜欢
  • 2011-01-14
  • 1970-01-01
  • 2022-01-27
  • 2018-07-09
  • 2014-03-24
  • 1970-01-01
  • 2020-11-24
  • 2019-07-12
  • 1970-01-01
相关资源
最近更新 更多