如何创建一个新列,该列包含列表中最大的值,该值小于现有列中的单元格值



我有一个看起来像:

的pandas dataframe
     a   
0    0   
1   -2  
2    4  
3    1  
4    6  

我也有一个列表

A = [-1, 2, 5, 7]

我想添加一个名为" B"的新列,该列包含A中最大的值,该值小于列中的单元格值。如果没有这样的值,我希望" b"中的值为" x"。因此,目标是获得:

    a   b
0   0  -1
1  -2   X
2   4   2
3   1  -1
4   6   5

我该如何实现?

有一个构建功能merge_asof

s=pd.DataFrame({'a':A,'b':A})
pd.merge_asof(df.assign(index=df.index).sort_values('a'),s,on='a').set_index('index').sort_index().fillna('X')
Out[284]: 
       a  b
index      
0      0 -1
1     -2  X
2      4  2
3      1 -1
4      6  5
def largest_min(x):
    less_than = list(filter(lambda l: l < x, A))
    if len(less_than):
       return max(less_than)
    return 'X'
df['b'] = df['a'].apply(largest_min)

编辑:修复错误和'x'的未找到的值

不确定pandas方法,但是numpy.searchsorted在这里是一个完美的适合。

找到应插入元素以保持顺序的索引。

一旦将元素插入以维护排序的索引后,您就可以在查找阵列中查看这些索引的的元素,以找到最接近的较小元素。如果将元素插入列表的开头(索引0),我们知道查找列表中不存在较小的元素,我们使用np.where

来考虑该方案。
A = np.array([-1, 2, 5, 7])
r = np.searchsorted(A, df.a.values)
df.assign(b=np.where(r == 0, np.nan, A[r-1])).fillna('X')

   a  b
0  0 -1
1 -2  X
2  4  2
3  1 -1
4  6  5

此方法将比这里的apply快得多。

df = pd.concat([df]*10_000)
%%timeit
r = np.searchsorted(A, df.a.values)
df.assign(b=np.where(r == 0, np.nan, A[r-1])).fillna('X')
6.09 ms ± 367 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%timeit df['a'].apply(largest_min)
196 ms ± 5.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

这也是另一种方法:

df1 = pd.Series(A)
def filler(val):
    v = df1[df1 < val.iloc[0]].max()
    return v
df.assign(b=df.apply(filler, axis=1).fillna('X'))
   a  b
0  0 -1
1 -2  X
2  4  2
3  1 -1
4  6  5
df = pd.DataFrame({'a':[0,1,4,1,6]})
A = [-1,2,5,7]
new_list = []
for i in df.iterrows():
    for j in range(len(A)):
        if A[j] < i[1]['a']:
            print(A[j])
            pass
        elif j == 0:
            new_list.append(A[j])
            break
        else:
            new_list.append(A[j-1])
            break
df['b'] = new_list

最新更新