【问题标题】:creating a function that takes into multiple dataframe columns and spilt value across the columns创建一个函数,该函数接受多个数据框列并跨列溢出值
【发布时间】:2021-07-22 09:40:33
【问题描述】:

我有一个包含客户数据和销售团队的销售数据框。我有一个基于单个客户的目标电话,我想将其分配给各个销售团队

 cust_id| total_calls_req| group_1_rep| group_2_rep| group_3_rep
 34523  |    10          | 230429     | nan        | 583985
 34583  |    12          | 230429     | 539409     | 583985
 34455  |    6           | 135552     | nan        | nan

我想创建一个函数,根据是否分配了 group_rep,将 total_calls_req 拆分到每个组中。

如果 cust_id 分配给 1 个代表,则 total_calls_req 全部分配给相关代表

如果 cust_id 分配给 2 个代表,则 total_calls_req 将分配给有问题的两个代表。

如果cust_id 分配给 3 个代表,那么 total_calls_req 会在三个代表之间随机分配,并且需要是整张卡片。

我希望最终数据框看起来像这样:

 cust_id| total_calls_req| group_1_rep| group_2_rep| group_3_rep| group_1_rep_calls| group_2_rep_calls| group_3_rep_calls
 34523  |    10          | 230429     | nan        | 583985     |   5              | 0                |   5
 34583  |    12          | 230429     | 539409     | 583985     |   6              | 3                |   3
 34455  |    6           | 135552     | nan        | nan        |   6              | 0                |   0

有没有办法通过 python 函数做到这一点?

【问题讨论】:

  • 所以 3 次代表和随机拆分的情况意味着加起来为 12 的呼叫的任何组合(在示例中)?你显示 6-3-3。可以是 10-1-1 还是 0-4-8 等?如果 2-rep 案例的调用次数为奇数怎么办?
  • @jch 是的,它可以是任何随机组合。如果它是奇数,那么你想拆分为任何一个,但它需要是整数加起来
  • @dsexplorer 对答案有任何反馈吗?其中一个解决了您的问题吗?

标签: python pandas dataframe


【解决方案1】:

您可以构建一个函数,该函数根据NaN 值的数量返回一个包含三个元素的系列。我在this answer 获得系列,在那个答案中使用numpy.random.multinomial

import numpy as np    

def serie_split(row):
  total_calls_req = row[0]
  groups = row[1:]
  numbers_nan = pd.notna(groups).sum()
  if numbers_nan == len(groups):
    s = pd.Series(np.random.multinomial(total_calls_req, [1/len(groups)] * len(groups)))
  else:
    s = pd.Series(groups)
    s.loc[s.notna()] = total_calls_req/numbers_nan if (total_calls_req % 2) == 0 else np.random.multinomial(total_calls_req, [1/numbers_nan] * numbers_nan)
    s.loc[s.isna()] = 0
  return s

def get_rep_calls(df):
  columns = df.filter(like='group_').add_suffix('_calls').columns
  dfg = df[df.columns[1:]] # dfg is a dataframe only with the columns 'total_calls_req','group_1_rep', 'group_2_rep' and 'group_3_rep'
  series = [serie_split(row) for row in dfg.to_numpy(dtype='object')]
  for index in range(len(dfg)):
    df.loc[index, columns] = series[index].values

get_rep_calls(df)
print(df)

输出 (我在最后一行用total_calls_req = 13添加了一个例子)

cust_id total_calls_req group_1_rep group_2_rep group_3_rep group_1_rep_calls group_2_rep_calls group_3_rep_calls
34523 10 230429 NaN 583985 5 0 5
34583 12 230429 539409 583985 4 7 1
34455 6 135552 NaN NaN 6 0 0
12345 13 123456 NaN 583985 10 0 3

【讨论】:

  • 谢谢。我怎样才能拆分奇数值,以便我得到整数并仍然添加到总数中?有什么我可以添加到这一行的吗s.loc[s.isna()] = total_calls_req / numbers_nan
  • 你可以用np.random.multinomial做点什么。给我一秒钟..
  • @dsexplorer 我已经更新了我的答案,请再次测试
【解决方案2】:

您可以使用此自定义 split 函数在分配给客户的代表之间分配呼叫。这使用以“group_”开头的列来识别分配的代表并计算他们的数量。如果它们超过两个,numpy.random.multinomial 函数可以生成随机拆分。

import numpy as np

def split(s):
    reps = (~s.filter(like='group_').isna()).astype(int).add_suffix('_calls')
    total = reps.sum()
    if total > 2:   # remove this line and below for a better split across reps
        return np.random.multinomial(s['total_calls_req'], [1/total]*total)
    div, mod = divmod(int(s['total_calls_req']), total)
    reps = reps*div # split evenly
    reps[np.random.choice(np.flatnonzero(reps), mod)]+=1 # allocate remainder randomly
    return reps

pd.concat([df, df.apply(split, axis=1)], axis=1)

输出:

   cust_id  total_calls_req  group_1_rep  group_2_rep  group_3_rep  group_1_rep_calls  group_2_rep_calls  group_3_rep_calls
0    34523               10       230429          NaN     583985.0                  5                  0                  5
1    34583               12       230429     539409.0     583985.0                  4                  2                  6
2    34455                6       135552          NaN          NaN                  6                  0                  0

【讨论】:

  • 谢谢。我如何拆分奇数值以便得到整数。我还将 astype 更改为 string 以帮助捕获任何空值。
  • 我为此更新了代码。您可以通过删除if total > 2: 行和之后的行来简化它。这将导致在所有情况下公平拆分(即使 reps > 2)
猜你喜欢
  • 1970-01-01
  • 2019-04-30
  • 1970-01-01
  • 1970-01-01
  • 2020-07-20
  • 1970-01-01
  • 1970-01-01
  • 2021-03-19
  • 1970-01-01
相关资源
最近更新 更多