【问题标题】:How Can I optimise my code further using Pandas for the required Problem如何使用 Pandas 进一步优化我的代码以解决所需的问题
【发布时间】:2020-10-15 14:27:00
【问题描述】:

我已经创建了以下数据集

dataset1 = { 'srid':[1,2,3,1,5],
            'custid':[11,12,43,12,34],
            'orderdate':["1/2/2019","1/2/2019","2/2/2019","1/2/2019","1/2/2019"],
            'Rev':[100,101,102,103,17]
}

df1 = pd.DataFrame(dataset1)

我必须将每个销售代表标记为: 优秀(他一天的总收入是平均收入的 1.5 倍或更多) 当天的所有销售代表) 好(他一天的总收入小于 1.5 倍且大于等于 1.1 乘以当天所有销售代表的平均收入) 平均(他一天的总收入小于 1.1 倍且大于等于 为当天所有销售代表平均收入的 0.9 倍) 差(他一天的总收入低于所有人平均收入的 0.9 倍) 当天的销售代表)对于“数据集 1”中存在的每个日期 输出数据集:销售代表 ID、订单日期、标记

我尝试的是:

g=df.groupby(df['orderdate'])
ans={}
for od,od_df in g:
   # print(od)
    ans[od]=list()
    x=od_df["Rev"].mean()
    s=set(od_df["srid"].tolist())
    for i in s:
        p=od_df[od_df["srid"]==i]["Rev"].sum()
        val = p/x
        if val>=1.5:
            ans[od].append([i,od,"Excellent"])
        elif 1.1<=val<1.5:
            ans[od].append([i,od,"good"])
        elif 0.9<=val<1.1:
            ans[od].append([i,od,"avg"])
        else:
            ans[od].append([i,od,"poor"])

但是要写的内容很多,并且需要更多时间在大数据集上,我该如何进一步优化它

【问题讨论】:

  • 预期输出是什么?
  • 输出:销售代表ID、订单日期、标记

标签: python pandas


【解决方案1】:

我会做这样的事情

list_df = []
for date in df.orderdate.unique():
    df_cur = df[df.orderdate==date]
    mean = df_cur.rev.Mean()
    def get_rank(rev):
        if rev > 1.5*mean:
           return "Good"
        elif rev .......
    df_cur["Ranking"]=df_cur.rev.apply(get_rank)
    list_df.append(df_cur)
df_final = pd.concat(list_df)

我的意思是,你需要调整它,但我认为它应该可以工作

对于每个日期,我得到以下数据框,然后得到当天的排名。最后,我合并所有数据框以获取所有日期。

【讨论】:

  • 为什么要在循环中定义函数?当apply应用于整个系列时,为什么要循环调用它?
  • 排名和排名取决于日期,因此给出排名的函数随每个日期而变化。对于每个日期,我得到以下数据框,然后得到当天的排名。最后,我合并所有数据框以获取所有日期。
【解决方案2】:

只需添加要计算的列并“应用”到结果

df1['mean'] = df1.loc[:,['orderdate','Rev']].groupby('orderdate').transform('mean')
df1['Representative'] = df1['Rev']/df1['mean']

def rep(x):
    if x >= 1.5:
        return 'Excellent'
    elif 1.1<=x<1.5:
        return 'good'
    elif 0.9<=x<1.1:
        return 'avg'
    else:
        return 'poor'

df1['Marking'] = df1['Representative'].apply(rep)
df1
    srid    custid  orderdate   Rev mean    Representative  Marking
0   1   11  1/2/2019    100 80.25   1.246106    good
1   2   12  1/2/2019    101 80.25   1.258567    good
2   3   43  2/2/2019    102 102.00  1.000000    avg
3   1   12  1/2/2019    103 80.25   1.283489    good
4   5   34  1/2/2019    17  80.25   0.211838    poor

【讨论】:

  • 谢谢,这真的很有帮助.. 你能推荐一些好的资源来学习使用 groupby 和 trasform 编写复杂的查询
  • 我也不知道有哪个网站能详细解释,但我刚查了一下发现SOSOTDS等。
【解决方案3】:

与您的相比,我无法真正测试实现的速度,因为 5 个值比其他任何东西都更能衡量开销。然而,裸循环在 pandas 中往往效率很低。您可以像这样得到平均值的相对差异:

In [15]: df.groupby('orderdate').apply(lambda _df: _df['Rev'] / _df['Rev'].mean())                                                                                                                         
Out[15]: 
orderdate   
1/2/2019   0    1.2461
           1    1.2586
           3    1.2835
           4    0.2118
2/2/2019   2    1.0000
Name: Rev, dtype: float64

并使用pd.cut 将其转换为序数比例

In [28]: df['RevMark'] = pd.cut(df.groupby('orderdate').apply(lambda _df: _df['Rev'] / _df['Rev'].mean()).sort_index(level=1).values, [0,0.9,1.1,1.5,np.inf], labels=['poor', 'avg', 'good', 'excellent']) 

In [29]: df                                                                                                                                                                                                
Out[29]: 
   srid  custid orderdate  Rev RevMark
0     1      11  1/2/2019  100    good
1     2      12  1/2/2019  101    good
2     3      43  2/2/2019  102     avg
3     1      12  1/2/2019  103    good
4     5      34  1/2/2019   17    poor

sort_index 是必要的,因为分组后的值按日期排序,因此关联将是错误的。 cut 的第二个参数是你想要的区间的边界,标签是你所谓的标记。

就时间而言,您需要自己在足够大的样本上进行测量。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-01
    • 1970-01-01
    相关资源
    最近更新 更多