Python学习笔记:给定邮编,判断区域

一、背景

给定一个维表,如下:

区域	编码范围
N0	1000-1935, 2000-2079, 2085-2107
GF	2250-2263
WG	2500-2507, 2515-2532
NC	2282-2310
BR	3350, 3353-3356
V2	2648, 2715, 2717-2719
V3	3689-3690
Q5	4225

每一个区域编码,都会包含多个不同、不一定连续的编码,如编码范围列所示,要求给定一个编码值,求所对应的区域。

二、思路

1.思路一

将编码范围进行拆分,构造出每一个编码与区域的键值对,生成一个字典,再进行值的查找。

实现最终效果如下:

0	N0	1000
1	N0	1001
2	N0	1002
3	N0	1003
4	N0	1004
5	N0	1005
......
9158	NT2	901
9159	NT2	902
9160	NT2	903
9161	NT2	904
9162	NT2	905

再通过列值的查找,即可返回对应的区域。

此方法计算量较大,需要将每一个编码跨度的每一个取值均生成出来。

2.思路二

后续优化的时候,考虑其实无须将每一个编码都生成 duck不必!,只需要判断编码是否连续。

连续的编码,取最小值(下限)、最大值(上限)构造两列。

非连续编码,令最大值=最小值。

如下所示:

    区域 Min_value Max_value
0   N0      1000      1935
1   N0      2000      2079
2   N0      2085      2107
3   GF      2250      2263
4   WG      2500      2507
5   WG      2515      2532
6   NC      2282      2310
7   BR      3350      3350
8   BR      3353      3356
9   V2      2648      2648
10  V2      2715      2715
11  V2      2717      2719
12  V3      3689      3690
13  Q5      4225      4225

最后通过判断:Min_value <= 编码 <= Max_value 即可。

3.思路三

类似于思路二,只是中间直接用 reset_index() + stack() 直接堆叠实现。

三、实操

1.思路一实操

# 追加 构造字典方式
import os
import pandas as pd
os.chdir(r'C:\Users\111\Desktop')

# 读取原始表
df = pd.read_excel(r'df.xlsx')
result = []

# 按行循环 效率低
for i in range(len(df)):
    # 每一行
    print(i)
    # 判断是否包括逗号
    if ',' not in str(df.loc[i, '编码范围']):
        # 判断是否包括横线
        if '-' not in str(df.loc[i, '编码范围']):
            # 不包括的直接追加结果表
            result.append([df.loc[i, '区域'], df.loc[i, '编码范围']])
        else:
            # 没逗号有横线的 切分为最小值,最大值,生成追加结果表
            a, b = [int(x) for x in df.loc[i, '编码范围'].split('-')]
            for x in range(a, b+1):
                # print(x)
                result.append([df.loc[i, '区域'], x])
    # 有逗号
    else:
        for y in df.loc[i, '编码范围'].split(','):
            # print(y)
            # 有逗号 没横线 直接追加
            if '-' not in y:
                result.append([df.loc[i, '区域'], y])
                # print(y)
            else:
                #  有逗号有横线
                c, d = [int(x) for x in y.split('-')]
                # print(c, d)
                for x in range(c, d+1):
                    # print(x)
                    result.append([df.loc[i, '区域'], x])
                
result = pd.DataFrame(result, columns=['区域', '编码范围'])
result['编码范围'] = result['编码范围'].astype(int)
result.to_excel(r'result.xlsx')
result.sort_values(by='编码范围', inplace=True)
result.reset_index(drop=True, inplace=True)
result
'''
      区域  编码范围
0     N0  1000
1     N0  1001
2     N0  1002
3     N0  1003
4     N0  1004
  ..   ...
1116  BR  3355
1117  BR  3356
1118  V3  3689
1119  V3  3690
1120  Q5  4225

[1121 rows x 2 columns]
'''

2.思路二实操

  • 构造编码范围上下限
import os
import pandas as pd
os.chdir(r'C:\Users\111\Desktop')

# 读取数据
df = pd.read_excel(r'df.xlsx')
# 如果包含逗号则进行分列
df['编码范围'] = df['编码范围'].apply(lambda x: x.split(',') if ',' in str(x) else x)
# 炸裂 列转多行
df = df.explode('编码范围').reset_index(drop=True)
# 去除头尾多余的空格
df['编码范围'] = df['编码范围'].apply(lambda x: str(x).strip())
# 按横线切割再展开 构造最小值、最大值列
df[['Min_value', 'Max_value']] = df['编码范围'].str.split('-', expand=True).rename(columns={0:'Min_value', 1:'Max_value'})
# 最大值列为空填充为最小值
df.loc[df['Max_value'].isnull(), 'Max_value'] = df.loc[df['Max_value'].isnull(), 'Min_value']
# 转换为数值
df['Min_value'] = df['Min_value'].astype(int)
df['Max_value'] = df['Max_value'].astype(int)
# 查看类型
df.dtypes
'''
区域           object
编码范围         object
Min_value     int32
Max_value     int32
dtype: object
'''
#### 输出 ####
'''
    区域       编码范围 Min_value Max_value
0   N0  1000-1935      1000      1935
1   N0  2000-2079      2000      2079
2   N0  2085-2107      2085      2107
3   GF  2250-2263      2250      2263
4   WG  2500-2507      2500      2507
5   WG  2515-2532      2515      2532
6   NC  2282-2310      2282      2310
7   BR       3350      3350      3350
8   BR  3353-3356      3353      3356
9   V2       2648      2648      2648
10  V2       2715      2715      2715
11  V2  2717-2719      2717      2719
12  V3  3689-3690      3689      3690
13  Q5       4225      4225      4225
'''
  • 构造函数判断取值
def find_email(df, n):
    '''
    df    展开的维表
    n     待查找的编码
    '''
    is_or_not = (df['Min_value'] <= n) & (df['Max_value'] >= n)
    return df.loc[is_or_not, '区域'].values[0]

result = find_email(df, 2718)
print(f'所查找的邮编归属区域为:{result}')
# 所查找的邮编归属区域为:V2

3.思路三实操

# 直接堆叠
df = pd.read_excel(r'df.xlsx')
df.set_index('区域', inplace=True)
df['编码范围'] = df['编码范围'].astype(str)
df = df['编码范围'].str.split(',', expand=True)
df = df.stack().reset_index()[['区域', 0]].rename(columns={0: 'Code_min_max'})
df.set_index('区域', inplace=True)
df = df['Code_min_max'].str.split('-', expand=True).rename(columns={0:'Min', 1:'Max'}).reset_index()
df.loc[df['Max'].isnull(), 'Max'] = df.loc[df['Max'].isnull(), 'Min']

x = 2718
y = df.loc[(df['Min'].astype(int) < x) & ( df['Max'].astype(int) > x), '区域'].values[0]
posted @ 2022-01-28 16:34  Hider1214  阅读(321)  评论(0编辑  收藏  举报