【问题标题】:Python Numpy: Replace duplicate values with mean valuePython Numpy:用平均值替换重复值
【发布时间】:2015-04-12 21:54:34
【问题描述】:

我有两个测量值,位置和温度,它们以固定的采样率进行采样。某些位置可能在数据中出现多次。现在我想在位置而不是时间上绘制温度。我不想在同一位置显示两个点,而是想用给定位置的平均值替换温度测量值。如何在 python 中用 numpy 很好地做到这一点?

到目前为止,我的解决方案如下所示:

import matplotlib.pyplot as plt
import numpy as np

# x = Position Data
# y = Temperature Data
x = np.random.permutation([0, 1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9])
y = (x + np.random.rand(len(x)) * 1 - 0.5).round(2)

# Get correct order
idx = np.argsort(x)
x, y = x[idx], y[idx]
plt.plot(x, y)  # Plot with multiple points at same location

# Calculate means for dupplicates
new_x = []
new_y = []
skip_next = False
for idx in range(len(x)):
    if skip_next:
        skip_next = False
        continue
    if idx < len(x)-1 and x[idx] == x[idx+1]:
        new_x.append(x[idx])
        new_y.append((y[idx] + y[idx+1]) / 2)
        skip_next = True
    else:
        new_x.append(x[idx])
        new_y.append(y[idx])
        skip_next = False

x, y = np.array(new_x), np.array(new_y)
plt.plot(x, y)  # Plots desired output

此解决方案没有考虑到某些位置可能在数据中出现两次以上。要替换所有值,必须多次运行循环。我知道必须有更好的解决方案!

【问题讨论】:

    标签: python numpy signal-processing


    【解决方案1】:

    使用np.bincount 的一种方法-

    import numpy as np
    
    # x = Position Data
    # y = Temperature Data
    x = np.random.permutation([0, 1, 1, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9])
    y = (x + np.random.rand(len(x)) * 1 - 0.5).round(2)
    
    
    # Find unique sorted values for x
    x_new = np.unique(x)
    
    # Use bincount to get the accumulated summation for each unique x, and 
    # divide each summation by the respective count of each unique value in x
    y_new_mean= np.bincount(x, weights=y)/np.bincount(x)
    

    示例运行 -

    In [16]: x
    Out[16]: array([7, 0, 2, 8, 5, 4, 1, 9, 6, 8, 1, 3, 5])
    
    In [17]: y
    Out[17]: 
    array([ 6.7 ,  0.12,  2.33,  8.19,  5.19,  3.68,  0.62,  9.46,  6.01,
            8.  ,  1.07,  3.07,  5.01])
    
    In [18]: x_new
    Out[18]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    
    In [19]: y_new_mean
    Out[19]: 
    array([ 0.12 ,  0.845,  2.33 ,  3.07 ,  3.68 ,  5.1  ,  6.01 ,  6.7  ,
            8.095,  9.46 ])
    

    【讨论】:

    • 看起来不错并产生相同的确切结果是我的解决方案!让我们看看其他人是否提出了另一个好的解决方案,否则我去接受这个。
    • @jrast 当然!不着急。只是对此感到好奇 - 如果您有机会进行基准测试,您是否看到这种方法有任何加速?我预计这至少会有所加快。
    • 我只是将它与@Will 给出的解决方案进行了比较:我使用了一个包含 300000 个数据点的数据集,其中每个位置出现 3 次(因此 100000 个唯一位置。)您的解决方案:10 个循环,最好是 3 个:每个循环 20.6 毫秒,Will 的解决方案:1 个循环,最好的 3 个:每个循环 2.16 秒。我认为我最初的解决方案与 Will 的解决方案在同一范围内,因为它也使用循环。
    • 现在好像有人进入numpy :) +1。
    • 对这个解决方案再提一点:np.bincount 的行为有点出乎意料,输入必须是正数,并且 bin 总是从 0 开始,所以可能有一些 bin 是 0!因此,最终结果必须从数组中可能存在的任何 nan 中清除,这是除以零的结果。
    【解决方案2】:

    如果我理解您的要求,这里有一种更简单的方法。

    给定一些随机排列的数据集,但每个位置都与每个温度相关:

    data = np.random.permutation([(1, 5.6), (1, 3.4), (1, 4.5), (2, 5.3), (3, 2.2), (3, 6.8)])
    >> array([[ 3. ,  2.2],
       [ 3. ,  6.8],
       [ 1. ,  3.4],
       [ 1. ,  5.6],
       [ 2. ,  5.3],
       [ 1. ,  4.5]])
    

    我们可以对字典中的每个位置进行排序并将其作为键,同时在字典中的数组中跟踪该位置的温度。我们在这里使用了一些错误处理,如果键(位置)还没有在我们的字典中,python 会抱怨 KeyError 所以我们添加它。

    results = {}
    for entry in sorted(data, key=lambda t: t[0]):
        try:
            results[entry[0]] = results[entry[0]] + [entry[1]]
        except KeyError:
            results[entry[0]] = [entry[1]]
    print(results)
    >> {1.0: [3.3999999999999999, 5.5999999999999996, 4.5],
     2.0: [5.2999999999999998],
     3.0: [2.2000000000000002, 6.7999999999999998]}
    

    通过最终的列表理解,我们可以将其展平并得到结果数组。

    np.array([[key, np.mean(results[key])] for key in results.keys()])
    >> array([[ 1. ,  4.5],
       [ 2. ,  5.3],
       [ 3. ,  4.5]])
    

    这可以放在一个函数中:

    def flatten_by_position(data):
        results = {}
        for entry in sorted(data, key=lambda t: t[0]):
            try:
                results[entry[0]] = results[entry[0]] + [entry[1]]
            except KeyError:
                results[entry[0]] = [entry[1]]
        return np.array([[key, np.mean(results[key])] for key in results.keys()])
    

    使用各种输入进行测试,此解决方案对于 1000000 个条目以下的数据集应该足够快。

    【讨论】:

      猜你喜欢
      • 2020-12-08
      • 2018-12-27
      • 2013-09-12
      • 2023-03-08
      • 1970-01-01
      • 1970-01-01
      • 2016-09-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多