CSV:如何从列表(包含列表的列表)中找到最接近的匹配/最接近的值?

时间:2021-06-13 09:49:41

标签: python pandas dataframe

我有一个代码可以读取包含 3 列的 CSV 文件中的一列:区域、网外呼叫和流量。

enter image description here

示例数据:

 Zone  Offnet calls  Traffic
zone0             0        0
zone1           421    30167
zone2           667    23172
zone3         12146   215033
zone4          7163   126514
zone5          5211   130045
zone6          1374    75357
zone7          3702   257846
zone8          1129    77677
zone9          2679    79331

我需要“网外通话”和“流量”来创建列表。例如,第 2 行将是 [421, 30167] 并从包含相同参数列表的列表中搜索最佳匹配/最接近的值。 看代码会更清楚:


tp_usp15 = [10, 200]
tp_usp23 = [15, 250]
tp_usp27 = [20, 300]
list_usp = [tp_usp15,tp_usp23, tp_usp27]

tp_bsnspls_s = [1,30]
tp_bsnspls_steel = [13,250]
tp_bsnspls_chrome = [18,350]
list_bsnspls = [tp_bsnspls_s,tp_bsnspls_steel,tp_bsnspls_chrome]

tp_bsnsrshn10 = [10,200]
tp_bsnsrshn15 = [15,300]
tp_bsnsrshn20 = [20,400]
list_bsnsrshn = [tp_bsnsrshn10,tp_bsnsrshn15,tp_bsnsrshn20]

common_list = list_usp + list_bsnspls + list_bsnsrshn

例如,从代码中提供的这个列表中,第 2 行 = [421, 30167] 的最接近值/最佳匹配是 [20, 400] = tp_bsnsrshn20。我需要一个代码来对 CSV 文件中的所有值进行相同的操作。最接近的值/最佳匹配需要记录到下一列(应在“流量”列旁边创建一个名为“最佳匹配”的新列)。我有一个适用于输入的代码。 2 个用户输入创建一个列表,搜索是从列表列表中完成的。

client_traffic = int(input("Enter the expected monthly traffic: "))
client_offnet = int(input("Enter monthly offnet calls: "))
list_client = [client_payment, client_offnet]

from functools import partial
def distance_squared(x, y):
    return (x[0] - y[0])**2 + (x[1] - y[1])**2
best_match_overall = min(common_list, key=partial(distance_squared, list_client))
name_best_match_overall = [k for k,v in locals().items() if v == best_match_overall][0]

如何将此代码应用于整个 CSV 文件。顺便说一下,它还给出了值的名称。我想高级用户应该不难创建一些循环,该循环将按照我在上一个代码中提供的相同概念但针对整个文件工作。在这一点上,我真的很挣扎。提前致谢,伙计们!

1 个答案:

答案 0 :(得分:1)

输入数据:

>>> df
    Zone  Offnet calls  Traffic
0  zone0             0        0
1  zone1           421    30167
2  zone2           667    23172
3  zone3         12146   215033
4  zone4          7163   126514
5  zone5          5211   130045
6  zone6          1374    75357
7  zone7          3702   257846
8  zone8          1129    77677
9  zone9          2679    79331

将您的参考列表构建为数据框:

ref = {'tp_usp15': [10, 200],
       'tp_usp23': [15, 250],
       'tp_usp27': [20, 300],
       'tp_bsnspls_s': [1, 30],
       'tp_bsnspls_steel': [13, 250],
       'tp_bsnspls_chrome': [18, 350],
       'tp_bsnsrshn10': [10, 200],
       'tp_bsnsrshn15': [15, 300],
       'tp_bsnsrshn20': [20, 400]}

df1 = pd.DataFrame(ref, index=['crit1', 'crit2']).T.rename_axis('Name')
df1['Best Match'] = list(map(list, df1.values))
>>> df1
                   crit1  crit2 Best Match
Name
tp_usp15              10    200  [10, 200]
tp_usp23              15    250  [15, 250]
tp_usp27              20    300  [20, 300]
tp_bsnspls_s           1     30    [1, 30]
tp_bsnspls_steel      13    250  [13, 250]
tp_bsnspls_chrome     18    350  [18, 350]
tp_bsnsrshn10         10    200  [10, 200]
tp_bsnsrshn15         15    300  [15, 300]
tp_bsnsrshn20         20    400  [20, 400]

dfdf1 创建笛卡尔积并计算平方距离:

cx = pd.merge(df.reset_index(), df1.reset_index(), how='cross')
x0, x1, y0, y1 = cx[['Offnet calls', 'Traffic', 'crit1', 'crit2']].values.T
cx['distance'] =  (x0 - y0)**2 + (x1 - y1)**2

保留每个 df 行的最接近值:

cols = ['index', 'Zone', 'Offnet calls', 'Traffic', 'Best Match', 'Name']
out = cx.loc[cx.groupby('index')['distance'].idxmin(), cols] \
        .set_index('index').rename_axis(None)

输出结果:

>>> out
    Zone  Offnet calls  Traffic Best Match           Name
0  zone0             0        0    [1, 30]   tp_bsnspls_s
1  zone1           421    30167  [20, 400]  tp_bsnsrshn20
2  zone2           667    23172  [20, 400]  tp_bsnsrshn20
3  zone3         12146   215033  [20, 400]  tp_bsnsrshn20
4  zone4          7163   126514  [20, 400]  tp_bsnsrshn20
5  zone5          5211   130045  [20, 400]  tp_bsnsrshn20
6  zone6          1374    75357  [20, 400]  tp_bsnsrshn20
7  zone7          3702   257846  [20, 400]  tp_bsnsrshn20
8  zone8          1129    77677  [20, 400]  tp_bsnsrshn20
9  zone9          2679    79331  [20, 400]  tp_bsnsrshn20