在按列分组时查找最接近的值

时间:2019-04-16 18:56:35

标签: python pandas

我想创建2个新列,这些列将为我提供最接近某个值的值和ID。这就是我在python中的df的结构:

x_time    expiration    x_price    p_time    p_price
 100          4          55.321     100        21
 105          4          51.120     105        25
 110          4          44.412     110        33.1
 100          5           9.1       100        3.1
 105          5           9.5       105        5.1
 110          5           8.2       110        12.1 
 100          6           122.1     100        155.9
 105          6           144.1     105        134.2 
 .......

本质上,我想创建一个新列(称为“ closest_time”和“ closest_price”),该列将仅是该组与x_price最为接近的p_price(因此该组将按过期时间显示)

因此,预期结果将如下所示:

x_time    expiration    x_price    p_time    p_price   closest_price closest_p_time
 100          4          55.321     100        21           33.1       110
 105          4          51.120     105        25           33.1       110
 110          4          44.412     110        33.1         33.1       110
 100          5           9.1       100        3.1          12.1       110
 105          5           9.5       105        5.1          12.1       110
 110          5           8.2       110        12.1          5.1       105
 100          6           122.1     100        155.9       134.2       105
 105          6           144.1     105        134.2       134.22      100

希望这有点道理。

我已经想到了执行此操作的潜在方法:

  1. 使用for循环
    • 第一个到期循环
    • 然后解析p_price并将所有值与每个x_price进行比较,然后选择最接近的值(min(abs())
    • 但是,这似乎是最长的解决方法-如果有一种向量化方法,那将是理想的选择!

但是,我没有成功。

谢谢!

3 个答案:

答案 0 :(得分:3)

我认为这是一个不错的解决方案:

df['closest_price'] = \
    df.apply(lambda x: df[df.p_price <= x.x_price]['p_price'].max(), axis=1)

答案 1 :(得分:2)

我不确定您的预期结果是否正确-最后一行似乎错了,144.1比155.9更接近134.2,因此,最近的_p_time应该为105?

我这样做的方法是先查找包含最接近值的行,然后为这些行选择价格和时间。

import io

d = """
x_time    expiration    x_price    p_time    p_price
 100          4          55.321     100        21
 105          4          51.120     105        25
 110          4          44.412     110        33.1
 100          5           9.1       100        3.1
 105          5           9.5       105        5.1
 110          5           8.2       110        12.1 
 100          6           122.1     100        155.9
 105          6           144.1     105        134.2 
"""

df = pd.read_csv(io.StringIO(d), delim_whitespace=True)

idx_lookup = df.apply(lambda x: (df.loc[df['expiration'] == x['expiration'], 'p_price'] - x['x_price']).abs().idxmin(), axis=1)

df['closest_p_price'] = df.loc[idx_lookup, 'p_price'].values
df['closest_p_time'] = df.loc[idx_lookup, 'p_time'].values

哪个给出了数据框

   x_time  expiration  x_price  p_time  p_price  closest_p_price  closest_p_time
0     100           4   55.321     100     21.0             33.1             110
1     105           4   51.120     105     25.0             33.1             110
2     110           4   44.412     110     33.1             33.1             110
3     100           5    9.100     100      3.1             12.1             110
4     105           5    9.500     105      5.1             12.1             110
5     110           5    8.200     110     12.1              5.1             105
6     100           6  122.100     100    155.9            134.2             105
7     105           6  144.100     105    134.2            134.2             105

请注意,此用法沿axis=1沿用,实际上贯穿每一行。我还没有想到更好的方法。

答案 2 :(得分:1)

好的,我的尝试。我使用的是自定义函数,该函数是从this帖子中获取的,该函数将一列转换为基于值的数组。然后,我使用groupby和transform运行您想要的数组以找到最接近的匹配项。

def find_nearest(array, values):
array = np.asarray(array)

    # the last dim must be 1 to broadcast in (array - values) below.
    values = np.expand_dims(values, axis=-1) 

    indices = np.abs(array - values).argmin(axis=-1)
    return array[indices]

    ## lets use a lambda with transform to assign this back to our main df 
    df['closest_price'] = df.groupby('expiration')['x_price'].transform(lambda x : find_nearest(df['p_price'],x))
    df['closest_time'] = df.groupby('expiration')['x_time'].transform(lambda x : find_nearest(df['p_time'],x))


     print(df)
    x_time  expiration  x_price p_time  p_price closest_price   closest_time
0   100     4   55.321      100 21.0    33.1    100
1   105     4   51.120      105 25.0    33.1    105
2   110     4   44.412      110 33.1    33.1    110
3   100     5   9.100       100 3.1     12.1    100
4   105     5   9.500       105 5.1     12.1    105
5   110     5   8.200       110 12.1    5.1     110
6   100     6   122.100     100 155.9   134.2   100
7   105     6   144.100     105 134.2   134.2   105