我想在数据框中创建一个新列,该列包含(在每个单元格中)数组中的第一个值,该值小于一个已经存在的列中每个相应单元格中的值。以下是有关此操作方式的简要说明,我确定了3种情况:
1.以5的步长创建a
并将其从10排列到75。
2a。如果列c1
在一个单元格中具有0到10的值,则新列的结果应为0
(我发现这很棘手,没有在数组a
上加上零。宁愿不做)。 c1
列始终为非负数。
2b。如果c1
是11到75,则它应返回a
的元素,该元素立即小于单元格的值。
2c。如果c1
大于75,则应返回75。(实际上,这只是2b的扩展)
这是我的尝试-它可以完成工作,但是我觉得它很慢。我认为我不能使用np.argmax
或np.argmin
,因为它们都不能完成上面的2a / b / c点。希望那里有一个更快的解决方案。
import numpy as np
import pandas as pd
np.random.seed(42)
N = 10**6 #number of rows in df, change this to lower values for testing
df = pd.DataFrame({'c1': np.random.randint(1,100,N)})
a = np.arange(10,80,5)
def first_lower(value, arr):
if len(arr[arr < value]) > 0:
return arr[arr < value][-1]
else:
return 0
def do_stuff(input_df):
df = input_df.copy()
df['NewCol'] = df['c1'].apply(lambda x: first_lower(x, a))
return df
%timeit do_stuff(df)
# 11.4 s ± 881 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
答案 0 :(得分:3)
设置
np.random.seed(1995)
df = pd.DataFrame({'c1': np.random.randint(1, 100, 10)})
a = np.arange(10,80,5)
选项1
您可以使用np.select
:
c1 = df.c1.isin(range(0, 11))
c2 = df.c1.isin(range(11,76))
r1 = 0
r2 = a[np.searchsorted(a, df.c1, side='left')-1]
np.select([c1, c2], [r1, r2], 75)
输出:
array([35, 75, 35, 50, 65, 25, 75, 50, 25, 65])
选项2
使用np.clip
:
s = np.clip(df.c1, 0, 75)
s[s.isin(range(11,75))] = a[np.searchsorted(a, df.c1)-1]
时间 :
df = pd.DataFrame({'c1': np.random.randint(1,100,10**6)})
%%timeit
c1 = df.c1.isin(range(0, 11))
c2 = df.c1.isin(range(11,76))
r1 = 0
r2 = a[np.searchsorted(a, df.c1, side='left')-1]
np.select([c1, c2], [r1, r2], 75)
# 104 ms ± 214 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
%%timeit
s = np.clip(df.c1, 0, 75)
s[s.isin(range(11,75))] = a[np.searchsorted(a, df.c1)-1]
# 96 ms ± 1.05 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
答案 1 :(得分:1)
类似于@ user3483203,但更通用:
import numpy as np
import pandas as pd
np.random.seed(42)
N = 20 # Just 20 for testing
df = pd.DataFrame({'c1': np.random.randint(1,100,N)})
a = np.arange(10,80,5)
idx = np.searchsorted(a, df.c1)
newcol = a[idx - 1]
newcol[idx == 0] = 0
df['newcol'] = newcol
print(df)
输出:
c1 newcol
0 52 50
1 93 75
2 15 10
3 72 70
4 61 60
5 21 20
6 83 75
7 87 75
8 75 70
9 75 70
10 88 75
11 24 20
12 3 0
13 22 20
14 53 50
15 2 0
16 88 75
17 30 25
18 38 35
19 2 0