【问题标题】:fast way to iterate through list, find duplicates and perform calculations快速遍历列表、查找重复项和执行计算的方法
【发布时间】:2020-07-24 06:35:59
【问题描述】:

我有两个列表,一个是区域,一个是价格,它们大小相同。

例如: 面积 = [1500,2000,2000,1800,2000,1500,500] 价格 = [200,800,600,800,1000,750,200]

我需要返回每个独特区域的价格列表,不包括原始区域。

所以对于 1500,我需要返回的列表是:[750] 和 [200] 对于 2000,我需要返回的列表是 [600,1000]、[800,1000] 和 [800,600] 对于 1800 和 500,我需要返回的列表都是空列表 []。

然后目标是确定一个值是否是异常值,取决于价格的绝对值 - 均值(不包括价格本身)小于 5 * 总体标准差(计算不包括价格本身)

    import statistics
area = [1500,2000,2000,1800,2000,1500,500]
price = [200,800,600,800,1000,750,200]         
outlier_idx = []
for idx, val in enumerate(area):
    comp_idx = [i for i, x in enumerate(area) if x == val]
    comp_idx.remove(idx)
    comp_price = [price[i] for i in comp_idx]
    if len(comp_price)>2:
        sigma = statistics.stdev(comp_price)
        p_m = statistics.mean(comp_price)
        if abs(price[idx]-p_m) > 5 * sigma:
            outlier_idx.append(idx)

area = [i for j, i in enumerate(area) if j not in outlier_idx]
price = [i for j, i in enumerate(price) if j not in outlier_idx]

问题是这个计算占用了大量时间,而且我正在处理可能非常大的数组。

我对如何提高计算效率感到困惑。

我愿意使用 numpy、pandas 或任何其他常见的包。

另外,我已经在pandas中尝试过这个问题:

df['p-p_m'] = ''
df['sigma'] = ''
df['outlier'] = False
for name, group in df.groupby('area'):
    if len(group)>1:
        idx = list(group.index)
        for i in range(len(idx)):
            tmp_idx = idx.copy()
            tmp_idx.pop(i)
            df['p-p_m'][idx[i]] = abs(group.price[idx[i]] - group.price[tmp_idx].mean())
            df['sigma'][idx[i]] = group.price[tmp_idx].std(ddof=0)
            if df['p-p_m'][idx[i]] > 3*df['sigma'][idx[i]]:
                df['outlier'][idx[i]] = True

谢谢。

【问题讨论】:

    标签: python python-3.x pandas performance numpy


    【解决方案1】:

    此代码是如何必须为每个区域创建列表:

    df = pd.DataFrame({'area': area, 'price': price})
    
    price_to_delete = [item for idx_array in df.groupby('price').groups.values() for item in idx_array[1:]]
    df.loc[price_to_delete, 'price'] = None
    
    df = df.groupby('area').agg(lambda x: [] if all(x.isnull()) else x.tolist())
    df
    

    我不明白你想要什么,但这部分是计算每个区域每个价格的异常值:

    df['outlier'] = False
    df['outlier'] = df['price'].map(lambda x: abs(np.array(x) - np.mean(x)) > 3*np.std(x) if len(x) > 0 else [])
    df
    

    我希望这对您有所帮助!

    【讨论】:

    • 如果您不明白 OP 想要什么,请要求澄清而不是发布答案。
    【解决方案2】:

    这是一个结合了NumpyNumba 的解决方案。虽然正确,但我没有针对效率方面的替代方法对其进行测试,但 Numba 通常会显着加快需要循环数据的任务的速度。根据您的定义,我添加了一个异常值。

    import numpy as np
    from numba import jit
    
    # data input
    price = np.array([200,800,600,800,1000,750,200, 2000])
    area = np.array([1500,2000,2000,1800,2000,1500,500, 1500])
    
    @jit(nopython=True)
    def outliers(price, area):
        is_outlier = np.full(len(price), False)
        for this_area in set(area):
            indexes = area == this_area
            these_prices = price[indexes]
            for this_price in set(these_prices):
                arr2 = these_prices[these_prices != this_price]
                if arr2.size > 1:
                    std = arr2.std()
                    mean = arr2.mean()
                    indices = (this_price == price) & (this_area == area)
                    is_outlier[indices] = np.abs(mean - this_price) > 5 * std
    
        return is_outlier 
    
    > outliers(price, area)
    > array([False, False, False, False, False, False, False,  True])
    

    如果每个区域有多个相同的价格水平,代码应该很快,因为它们会一次更新。

    我希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 2015-02-09
      • 2019-05-28
      • 2013-04-07
      • 1970-01-01
      • 1970-01-01
      • 2021-08-29
      • 2019-04-07
      • 1970-01-01
      • 2020-07-07
      相关资源
      最近更新 更多