import pandas as pd
# 创建示例数据
data = {
'itemId': ['A1', 'A2', 'A3', 'B1', 'B2', 'C1', 'C2', 'C3', 'D1', 'D2'],
'click_': [0.12, 0.15, 0.20, 0.05, 0.10, 0.25, 0.30, 0.35, 0.08, 0.18],
'category': ['Electronics', 'Electronics', 'Electronics', 'Books', 'Books',
'Clothing', 'Clothing', 'Clothing', 'Home', 'Home'],
'vol':[1,10,15,21,2,16,8,5,17,90]
}
# 创建数据框
df = pd.DataFrame(data)
# 显示数据框
display(df)
df['click_avg']=df.groupby('category')['click_'].transform('mean')
df['gt_avg']=df['click_']>df['click_avg']
def vol_fix(row):
vol=row['vol']
gt=row['gt_avg']
if vol<=10:
row['vol_new']=vol
else:
if gt:
row['vol_new']= vol+np.random.randint(0,10)
else:
row['vol_new']= vol-np.random.randint(0,10)
return row
df=df.apply(vol_fix,axis=1)
display(df)
要提高代码的效率,可以考虑避免在 apply 函数中使用循环和条件判断。我们可以通过矢量化操作来实现同样的逻辑,这样可以充分利用 Pandas 的性能优化。
以下是改进后的代码:
import pandas as pd
import numpy as np
# 创建示例数据
data = {
'itemId': ['A1', 'A2', 'A3', 'B1', 'B2', 'C1', 'C2', 'C3', 'D1', 'D2'],
'click_rate': [0.12, 0.15, 0.20, 0.05, 0.10, 0.25, 0.30, 0.35, 0.08, 0.18],
'category': ['Electronics', 'Electronics', 'Electronics', 'Books', 'Books',
'Clothing', 'Clothing', 'Clothing', 'Home', 'Home'],
'vol': [1, 10, 15, 21, 2, 16, 8, 5, 17, 90]
}
# 创建数据框
df = pd.DataFrame(data)
# 计算每个品类的平均点击率并添加到新列
df['click_rate_avg'] = df.groupby('category')['click_rate'].transform('mean')
# 添加一列表示点击率是否大于平均点击率
df['gt_avg'] = df['click_rate'] > df['click_rate_avg']
# 使用矢量化操作计算新的 vol 值
# 对于 vol <= 10 的行,vol_new 等于原始 vol
df['vol_new'] = df['vol']
# 对于 gt_avg 为 True 且 vol > 10 的行,vol_new 增加随机值
df.loc[(df['gt_avg'] == True) & (df['vol'] > 10), 'vol_new'] += np.random.randint(0, 10, df.loc[(df['gt_avg'] == True) & (df['vol'] > 10), 'vol_new'].shape[0])
# 对于 gt_avg 为 False 且 vol > 10 的行,vol_new 减少随机值
df.loc[(df['gt_avg'] == False) & (df['vol'] > 10), 'vol_new'] -= np.random.randint(0, 10, df.loc[(df['gt_avg'] == False) & (df['vol'] > 10), 'vol_new'].shape[0])
# 显示数据框
display(df)
解释:
- 创建示例数据框:包含
itemId、click_rate、category和vol列。 - 计算每个品类的平均点击率:使用
groupby和transform('mean')计算每个品类的平均点击率,并将结果添加到click_rate_avg列。 - 添加比较列:创建一个新列
gt_avg,表示click_rate是否大于click_rate_avg。 - 使用矢量化操作计算新的
vol值:- 对于
vol小于等于 10 的行,vol_new等于原始vol。 - 对于
gt_avg为True且vol大于 10 的行,vol_new增加一个随机值。 - 对于
gt_avg为False且vol大于 10 的行,vol_new减少一个随机值。
- 对于
- 显示结果:使用
display(df)显示数据框。
这种方法避免了使用 apply,大大提高了代码的执行效率。
df.loc[(df['gt_avg'] == True) & (df['vol'] > 10), 'vol_new'].shape[0]
解释df.loc[(df['gt_avg'] == True) & (df['vol'] > 10), 'vol_new'].shape[0]:
-
df.loc[...]:这是 Pandas 的.loc索引器,用于按标签或布尔条件进行访问。这里我们使用布尔条件选择满足特定条件的行。 -
条件
df['gt_avg'] == True:df['gt_avg']是一个布尔 Series,表示click_rate是否大于click_rate_avg。== True是显式检查,但可以简化为df['gt_avg'],因为布尔 Series 本身就表示True或False。
-
条件
df['vol'] > 10:- 这是一个布尔条件,表示
vol大于 10。
- 这是一个布尔条件,表示
-
组合条件
(df['gt_avg'] == True) & (df['vol'] > 10):- 使用按位与运算符
&将两个布尔条件组合,选择满足这两个条件的行。
- 使用按位与运算符
-
选择
vol_new列:df.loc[... , 'vol_new']选择满足条件的行的vol_new列。
-
.shape[0]:.shape属性返回数据框或 Series 的维度。对于 Series(或一维数组),shape是一个包含行数的元组。.shape[0]获取行数,即满足条件的行数。
这部分代码的目的是计算满足条件的行数,以便生成相同数量的随机数,从而在矢量化操作中更新 vol_new 列。例如:
import pandas as np
# 对于 gt_avg 为 True 且 vol > 10 的行,vol_new 增加随机值
num_rows = df.loc[(df['gt_avg'] == True) & (df['vol'] > 10), 'vol_new'].shape[0]
df.loc[(df['gt_avg'] == True) & (df['vol'] > 10), 'vol_new'] += np.random.randint(0, 10, num_rows)