作者:手机用户2502929183 | 来源:互联网 | 2023-08-14 22:08
Iamsettingupthefollowingexamplewhichissimilartomysituationanddata:我正在设置以下示例,该示例与我的情况和
I am setting up the following example which is similar to my situation and data:
我正在设置以下示例,该示例与我的情况和数据类似:
Say, I have the following DataFrame:
说,我有以下DataFrame:
df = pd.DataFrame ({'ID' : [1,2,3,4],
'price' : [25,30,34,40],
'Category' : ['small', 'medium','medium','small']})
Category ID price
0 small 1 25
1 medium 2 30
2 medium 3 34
3 small 4 40
Now, I have the following function, which returns the discount amount based on the following logic:
现在,我有以下功能,它根据以下逻辑返回折扣金额:
def mapper(price, category):
if category == 'small':
discount = 0.1 * price
else:
discount = 0.2 * price
return discount
Now I want the resulting DataFrame:
现在我想要生成的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
So I decided to call series.map on the column price because I don't want to use apply. I am working on a large DataFrame and map is much faster than apply.
所以我决定在列价上调用series.map,因为我不想使用apply。我正在处理大型DataFrame,并且映射比应用快得多。
I tried doing this:
我试过这样做:
for c in list(sample.Category.unique()):
sample[sample['Category'] == c]['Discount'] = sample[sample['Category'] == c]['price'].map(lambda x: mapper(x,c))
And that didn't work as I expected because I am trying to set a value on a copy of a slice of the DataFrame.
这并没有像我预期的那样工作,因为我试图在DataFrame片的副本上设置一个值。
My question is, Is there a way to do this without using df.apply()
?
我的问题是,有没有办法在不使用df.apply()的情况下执行此操作?
3 个解决方案
8
One approach with np.where
-
使用np.where的一种方法 -
mask = df.Category.values=='small'
df['Discount'] = np.where(mask,df.price*0.01, df.price*0.02)
Another way to put things a bit differently -
让事情有点不同的另一种方式 -
df['Discount'] = df.price*0.01
df['Discount'][df.Category.values!='small'] *= 2
For performance, you might want to work with array data, so we could use df.price.values
instead at places where df.price
was used.
为了提高性能,您可能希望使用数组数据,因此我们可以在使用df.price的地方使用df.price.values。
Benchmarking
Approaches -
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
Timings -
1) Large dataset :
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
2) Very large dataset :
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
Further boost with data reuse -
数据重用进一步提升 -
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
Timings -
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