我有一个看起来像:
的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