Rak*_*van 5 python numpy dataframe pandas
我正在设置以下示例,它类似于我的情况和数据:
说,我有以下DataFrame:
df = pd.DataFrame ({'ID' : [1,2,3,4],
'price' : [25,30,34,40],
'Category' : ['small', 'medium','medium','small']})
Run Code Online (Sandbox Code Playgroud)
Category ID price
0 small 1 25
1 medium 2 30
2 medium 3 34
3 small 4 40
Run Code Online (Sandbox Code Playgroud)
现在,我有以下功能,它根据以下逻辑返回折扣金额:
def mapper(price, category):
if category == 'small':
discount = 0.1 * price
else:
discount = 0.2 * price
return discount
Run Code Online (Sandbox Code Playgroud)
现在我想要生成的DataFrame:
Category ID price Discount
0 small 1 25 0.25
1 medium 2 30 0.6
2 medium 3 40 0.8
3 small 4 40 0.4
Run Code Online (Sandbox Code Playgroud)
所以我决定在列价上调用series.map,因为我不想使用apply.我正在处理一个大型DataFrame,地图比应用快得多.
我试过这样做:
for c in list(sample.Category.unique()):
sample[sample['Category'] == c]['Discount'] = sample[sample['Category'] == c]['price'].map(lambda x: mapper(x,c))
Run Code Online (Sandbox Code Playgroud)
这并没有像我预期的那样工作,因为我试图在DataFrame片的副本上设置一个值.
我的问题是,有没有办法不使用 df.apply()?
一种方法np.where-
mask = df.Category.values=='small'
df['Discount'] = np.where(mask,df.price*0.01, df.price*0.02)
Run Code Online (Sandbox Code Playgroud)
让事情有点不同的另一种方式 -
df['Discount'] = df.price*0.01
df['Discount'][df.Category.values!='small'] *= 2
Run Code Online (Sandbox Code Playgroud)
为了提高性能,您可能希望使用数组数据,因此我们可以在使用df.price.values的地方df.price使用.
方法 -
def app1(df): # Proposed app#1 here
mask = df.Category.values=='small'
df_price = df.price.values
df['Discount'] = np.where(mask,df_price*0.01, df_price*0.02)
return df
def app2(df): # Proposed app#2 here
df['Discount'] = df.price.values*0.01
df['Discount'][df.Category.values!='small'] *= 2
return df
def app3(df): # @piRSquared's soln
df.assign(
Discount=((1 - (df.Category.values == 'small')) + 1) / 100 * df.price.values)
return df
def app4(df): # @MaxU's soln
df.assign(Discount=df.price * df.Category.map({'small':0.01}).fillna(0.02))
return df
Run Code Online (Sandbox Code Playgroud)
计时 -
1)大数据集:
In [122]: df
Out[122]:
Category ID price Discount
0 small 1 25 0.25
1 medium 2 30 0.60
2 medium 3 34 0.68
3 small 4 40 0.40
In [123]: df1 = pd.concat([df]*1000,axis=0)
...: df2 = pd.concat([df]*1000,axis=0)
...: df3 = pd.concat([df]*1000,axis=0)
...: df4 = pd.concat([df]*1000,axis=0)
...:
In [124]: %timeit app1(df1)
...: %timeit app2(df2)
...: %timeit app3(df3)
...: %timeit app4(df4)
...:
1000 loops, best of 3: 209 µs per loop
10 loops, best of 3: 63.2 ms per loop
1000 loops, best of 3: 351 µs per loop
1000 loops, best of 3: 720 µs per loop
Run Code Online (Sandbox Code Playgroud)
2)非常大的数据集:
In [125]: df1 = pd.concat([df]*10000,axis=0)
...: df2 = pd.concat([df]*10000,axis=0)
...: df3 = pd.concat([df]*10000,axis=0)
...: df4 = pd.concat([df]*10000,axis=0)
...:
In [126]: %timeit app1(df1)
...: %timeit app2(df2)
...: %timeit app3(df3)
...: %timeit app4(df4)
...:
1000 loops, best of 3: 758 µs per loop
1 loops, best of 3: 2.78 s per loop
1000 loops, best of 3: 1.37 ms per loop
100 loops, best of 3: 2.57 ms per loop
Run Code Online (Sandbox Code Playgroud)
通过数据重用进一步提升 -
def app1_modified(df):
mask = df.Category.values=='small'
df_price = df.price.values*0.01
df['Discount'] = np.where(mask,df_price, df_price*2)
return df
Run Code Online (Sandbox Code Playgroud)
计时 -
In [133]: df1 = pd.concat([df]*10000,axis=0)
...: df2 = pd.concat([df]*10000,axis=0)
...: df3 = pd.concat([df]*10000,axis=0)
...: df4 = pd.concat([df]*10000,axis=0)
...:
In [134]: %timeit app1(df1)
1000 loops, best of 3: 699 µs per loop
In [135]: %timeit app1_modified(df1)
1000 loops, best of 3: 655 µs per loop
Run Code Online (Sandbox Code Playgroud)