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

时间:2019-02-15 19:53:12

标签: python pandas dataframe

我有一个熊猫数据框,看起来像:

     a   
0    0   
1   -2  
2    4  
3    1  
4    6  

我也有一个列表

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

我想添加一个名为“ b”的新列,该列包含A中的最大值,该值小于列“ a”中的单元格值。如果不存在这样的值,则我希望“ b”中的值为“ X”。因此,目标是获得:

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

我该如何实现?

5 个答案:

答案 0 :(得分: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

答案 1 :(得分:2)

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'

答案 2 :(得分:2)

不确定是否使用pandas方法,但是numpy.searchsorted在这里很合适。

  

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

一旦有了插入元素以保持排序的索引,就可以在查找数组中查看这些索引的 left 左边的元素,以找到最接近的较小元素。如果将元素插入列表的开头(索引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)

答案 3 :(得分:0)

这也是另一种方法:

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

答案 4 :(得分:-1)

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