1

我需要一些帮助,从我创建的客户数据集中过滤行。

该数据集包含客户 ID、保单编号以及与其保单相关的日期。客户可以随时在政策之间自由切换。以下数据集只是我放在一起的示例数据集。我可以使用 pandas 或 sql server 来筛选出合适的客户。

客观的:

我想在以下条件下过滤数据集并检索客户:

  • 客户必须按时间顺序使用保单利率13,然后切换到11
  • 客户必须拥有至少350 天的这两项政策。

我已经包含一个列 (policy_order) 显示订单活动策略。13 => 11 切换发生的时间无关紧要,只要跳跃是从 13 到 11,并且他们每次花费 350 天。

| row | cust_id | policy_num | policy_start | policy_end | policy_order | days_on_policy |
|-----|---------|------------|--------------|------------|--------------|----------------|
| 1   | 1000    | 17         | 09/23/2013   | 11/05/2013 | 1            | 43             |
| 2   | 1200    | 13         | 08/26/2011   | 04/30/2019 | 1            | 2804           |
| 3   | 3400    | 13         | 08/31/2012   | 02/22/2015 | 1            | 905            |
| 4   | 5000    | 17         | 04/12/2014   | 07/28/2014 | 1            | 107            |
| 5   | 5000    | 13         | 07/28/2014   | 08/24/2016 | 2            | 758            |
| 6   | 5000    | 11         | 08/24/2016   | 10/20/2018 | 3            | 787            |
| 7   | 5000    | 13         | 10/20/2018   | 05/02/2019 | 4            | 194            |
| 8   | 7600    | 13         | 02/02/2015   | 05/03/2019 | 1            | 1551           |
| 9   | 4300    | 11         | 01/07/2015   | 05/04/2017 | 1            | 848            |
| 10  | 4300    | 13         | 05/04/2017   | 05/05/2019 | 2            | 731            |
| 11  | 9800    | 13         | 12/12/2001   | 10/06/2015 | 1            | 5046           |
| 12  | 9800    | 11         | 10/06/2015   | 05/06/2019 | 2            | 1308           |

如上表所示,有两个客户符合条件。客户 5000 和客户 9800。我以客户 5000 为例,因为他们已经多次切换策略,但仍然满足第 5 行和第 6 行中的条件。这是我唯一关心的行。

所以我想看到的输出看起来像这样:

| row | acct | policy_num | policy_start | policy_end | policy_order | days_on_policy |
|-----|------|------------|--------------|------------|--------------|----------------|
| 1   | 5000 | 13         | 7/28/2014    | 8/24/2016  | 2            | 758            |
| 2   | 5000 | 11         | 8/24/2016    | 10/20/2018 | 3            | 787            |
| 3   | 9800 | 13         | 12/12/2001   | 10/6/2015  | 1            | 5046           |
| 4   | 9800 | 11         | 10/6/2015    | 5/6/2019   | 2            | 1308           |

结果将显示客户 ID、正确的保单编号、相关日期以及他们在每份保单上的天数。

我尝试过使用 SQL 中的 WHERE 子句进行过滤(我承认我不擅长),但还没有接近答案——甚至不知道从哪里开始。

我的主要目标是尝试使用订单、保单编号和保单天数过滤行。

非常感谢任何和所有帮助!

4

5 回答 5

0

这是我猜你需要的。

SELECT * 
FROM policy p1
WHERE policy_num = 13 
AND days_on_policy >= 350
AND EXISTS 
  (SELECT 1 FROM policy p2 
   WHERE p1.cust_id = p2.cust_id
     AND p2.policy_num =11
     AND p2.policy_start >= p1.policy_end
     AND p2.days_on_policy >= 350)
UNION ALL
SELECT * 
FROM policy p1
where policy_num = 11
AND days_on_policy >= 350
AND EXISTS 
  (SELECT 1 FROM policy p2 
   WHERE p1.cust_id = p2.cust_id
     AND p2.policy_num =13
     AND p1.policy_start >= p2.policy_end
     AND p2.days_on_policy >= 350)

SQLFiddler

于 2019-07-22T20:13:14.203 回答
0

使用自联接和应用于 ON 子句的条件:

select t1.*
from tablename t1 inner join tablename t2
on 
  t2.cust_id = t1.cust_id 
  and (
    (t2.policy_start = t1.policy_end) and (t1.policy_num = 13 and t2.policy_num = 11)
    or
    (t1.policy_start = t2.policy_end) and (t2.policy_num = 13 and t1.policy_num = 11)
  ) 
  and t1.days_on_policy  >= 350 and t2.days_on_policy >= 350
  order by t1.cust_id, t1.policy_start

请参阅演示
结果:

> row | cust_id | policy_num | policy_start        | policy_end          | policy_order | days_on_policy
> --: | ------: | ---------: | :------------------ | :------------------ | -----------: | -------------:
>   5 |    5000 |         13 | 28/07/2014 00:00:00 | 24/08/2016 00:00:00 |            2 |            758
>   6 |    5000 |         11 | 24/08/2016 00:00:00 | 20/10/2018 00:00:00 |            3 |            787
>  11 |    9800 |         13 | 12/12/2001 00:00:00 | 06/10/2015 00:00:00 |            1 |           5046
>  12 |    9800 |         11 | 06/10/2015 00:00:00 | 06/05/2019 00:00:00 |            2 |           1308
于 2019-07-22T20:17:41.563 回答
0

如果您想要基于Pandas的解决方案,则定义以下过滤函数:

def fltr(gr):
    wrk = gr.query('policy_num in [11, 13]').sort_values(['policy_order'])
    pNum = wrk.set_index('policy_order').policy_num
    if ~((pNum == 11).any() and (pNum == 13).any()):
        return None
    ind11 = pNum[pNum == 11].index[0]
    ind13 = pNum[pNum == 13].index[0]
    if ind13 > ind11:
        return None
    if (wrk.groupby('policy_num').days_on_policy.sum() >= 350).all():
        return wrk.drop_duplicates(subset='policy_num')
    return None

然后在groupby中使用它:

df.groupby('cust_id').apply(fltr)

过滤功能的简短描述

它从计算辅助变量开始:

  • wrk - policy_num == 1113的当前组的行,按policy_order 排序
  • wrk 中的 pNum - policy_num列,由policy_order索引

过滤函数有 2 个“初始”场合返回空内容(None),拒绝当前组:

  1. pNum未能包含至少一个11和至少一个13
  2. pNum中前13 个元素的索引(实际上是policy_order ) 大于前11 个元素的索引(策略13遵循策略11)。

最后一个决定是基于一个问题:每个有问题的策略(1113)是否具有days_on_policy >= 350 的总和?如果是,则该函数从wrk返回行而不重复,以删除可能的最后13行(如组5000的情况)。

否则,当前组也被拒绝。

于 2019-07-22T20:35:30.133 回答
0

过滤查询中的数据几乎总是更好,除非数据库的性能受到查询的影响。

如果您的数据集不是很大,这是我用来过滤的过程。

#filter on the criteria for the policy number 
df_13_fltr = df[(df['policy_num']==13)&\
                (df['days_on_policy']>=350)][['row','cust_id','policy_end']]
df_11_fltr = df[(df['policy_num']==11)&\
                (df['days_on_policy']>=350)][['row','cust_id','policy_start']]

#merge the 2 filtered DataFrames together and compare the policy_end and policy_start
df_fltr = df_11_fltr.merge(df_13_fltr, on='cust_id',how='inner',suffixes=('13','11'))
df_fltr =df_fltr[df_fltr['policy_end']<=df_fltr['policy_start']][['row13','row11']]

#put the rows in a list
rows = list(df_fltr['row13'].values)+list(df_fltr['row11'])

#using the rows list in a lambda filter on the original dataset
df[df['row'].apply(lambda x: x in rows)]
于 2019-07-22T21:09:54.497 回答
0

我在 cust_id 上使用了 groupby 并使用滚动窗口来回顾 policy_num 以找到 11 个当前和 13 个以前的。我原本想在 350 天创建一个过滤器,但因为它可能会破坏 policy_num 的顺序而将其注释掉

 data = """
 | row | cust_id | policy_num | policy_start | policy_end | policy_order |      days_on_policy |
 | 1   | 1000    | 17         | 09/23/2013   | 11/05/2013 | 1            | 43                  |
 | 2   | 1200    | 13         | 08/26/2011   | 04/30/2019 | 1            | 2804                |
 | 3   | 3400    | 13         | 08/31/2012   | 02/22/2015 | 1            | 905                 |
 | 4   | 5000    | 17         | 04/12/2014   | 07/28/2014 | 1            | 107                 |
 | 5   | 5000    | 13         | 07/28/2014   | 08/24/2016 | 2            | 758                 |
 | 6   | 5000    | 11         | 08/24/2016   | 10/20/2018 | 3            | 787                 |
 | 7   | 5000    | 13         | 10/20/2018   | 05/02/2019 | 4            | 194                 |
 | 8   | 7600    | 13         | 02/02/2015   | 05/03/2019 | 1            | 1551           |
 | 9   | 4300    | 11         | 01/07/2015   | 05/04/2017 | 1            | 848                 |
 | 10  | 4300    | 13         | 05/04/2017   | 05/05/2019 | 2            | 731                 |
 | 11  | 9800    | 13         | 12/12/2001   | 10/06/2015 | 1            | 5046           |
 | 12  | 9800    | 11         | 10/06/2015   | 05/06/2019 | 2            | 1308           |

"""

 data = data.strip().split('\n')
 data = [i.strip().split('|') for i in data]
 data = [i[1:-1] for i in data]
 columns=[data.strip() for data in data[0]]

 df = pd.DataFrame(data[1:], columns=columns)
 print(df.columns)
 df.set_index(['row'],inplace=True)
 # set the datatypes for each column
 df['cust_id'] = df['cust_id'].astype(int)
 df['policy_num'] = df['policy_num'].astype(int)
 df['policy_start'] = pd.to_datetime(df['policy_start'])
 df['policy_end'] = pd.to_datetime(df['policy_end'])
 df['policy_order'] = df['policy_order'].astype(int)
 df['days_on_policy'] = df['days_on_policy'].astype(int)
 #print(df)

 def create_filter(df, filter_cols, filter_values,operator_values):
     filter_list = []
     for col, val,operator in zip(filter_cols, filter_values,operator_values):
         if operator=='>':
             filter_list.append(df[col] > val)
         elif operator=='>=':
             filter_list.append(df[col] >= val)
         elif operator=='<':
             filter_list.append(df[col] < val)
         elif operator=='<=':
             filter_list.append(df[col] <= val)
         elif operator=='==':
             filter_list.append(df[col] == val)
     return pd.concat(filter_list, axis=1).all(axis=1)
 
 #filter_cols=['days_on_policy']
 #filter_values=[350]
 #operator_values=['>']
 #filter=create_filter(df, filter_cols, filter_values,operator_values)
 #df=df[filter]

 df = df.sort_values(by=['cust_id','policy_order'], ascending=False)
 #print(df)

 df_grouped = df.groupby('cust_id')
 rolling_df=df_grouped.rolling(window=1).sum()
 prev_key,prev_policy_num,prev_days_on_policy=tuple(),"",""
 prev_key=None
 for key,item in rolling_df.iterrows():
     policy_num=item['policy_num']
     days_on_policy=item['days_on_policy']
     if prev_key!=None:
         prev_policy_num,prev_days_on_policy=rolling_df.loc[prev_key]     [['policy_num','days_on_policy']]
         if key[0]==prev_key[0] and policy_num==13 and prev_policy_num==11 and prev_days_on_policy>350 and days_on_policy>350:
        print(prev_key[0],prev_policy_num)
     prev_key=key

输出:

5000 11.0
9800 11.0
于 2021-09-15T19:54:39.633 回答