【问题标题】:CSV: How to find a closest match/closest value from the list of lists (list that contains lists)?CSV:如何从列表列表(包含列表的列表)中找到最接近的匹配/最接近的值?
【发布时间】:2021-06-13 09:49:41
【问题描述】:

我有一个代码读取 CSV 文件中的一列,该文件包含 3 列:区域、离线呼叫和流量。

样本数据:

 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 文件。顺便说一句,它还给出了值的名称。我想高级用户应该不难创建一些循环,这些循环将按照我在上一个代码中提供的相同概念工作,但适用于整个文件。在这一点上我真的很挣扎。提前谢谢各位!

【问题讨论】:

  • 注意:应避免在您的问题中使用 CSV 数据的 Excel 屏幕截图,因为它使我们无法复制/粘贴数据进行测试。原始逗号分隔文本更好。此外,您真的不应该依赖变量名称(以及您对locals() 的使用),将名称作为数据结构的一部分包含在内要好得多。您甚至可以将其作为不同的 CSV 文件读入
  • @MartinEvans 如果您需要复制/粘贴,请添加前十行。有什么代码想法吗?

标签: python pandas dataframe


【解决方案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

【讨论】:

  • @ThomasCuisance,我看到您发布了另一个关于查找最佳匹配/最接近值的问题。我对这个问题的回答是否正确?如果是,请接受答案,以通知其他有类似问题的用户答案是正确的。
  • 实际上,我发布了另一个关于通过 3 个参数而不是 2 个参数搜索最接近值的问题。请看一下:stackoverflow.com/questions/68045098/…
猜你喜欢
  • 2021-08-29
  • 2018-11-24
  • 1970-01-01
  • 2012-11-14
  • 2015-07-26
  • 2021-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多