【问题标题】:pairs of rows with the highest string similarity字符串相似度最高的行对
【发布时间】:2021-11-17 14:36:40
【问题描述】:

所以我有这个数据框:

import pandas as pd
d = {'id': [1,1,1,1,2,2,3,3,3,4,4,4,4],
     'name':['ada','aad','ada','ada','dddd','fdd','ccc','cccd','ood','aaa','aaa','aar','rrp']
    ,'amount':[2,-12,12,-12,5,-5,2,3,-5,3,-10,10,-10]}
df1 = pd.DataFrame(d)
df1
    id  name    amount
0   1   ada      2
1   1   aad     -12
2   1   ada      12
3   1   ada    -12
4   2   dddd    5
5   2   fdd    -5
6   3   ccc     2 
7   3   cccd    3
8   3   ood    -5
9   4   aaa     3
10  4   aaa    -10
11  4   aar     10
12  4   rrp    -10 

首先,我想为每个 id 的负数找到匹配的正数,我通过以下方式完成:

def match_pos_neg(df):
    return df[df["amount"].isin(-df["amount"])]

df1 = df1.groupby("id").apply(match_pos_neg).reset_index(0, drop=True)
df1
    id  name  amount
1   1   aad   -12
2   1   ada   12
3   1   ada   -12
4   2   dddd    5
5   2   fdd    -5
10  4   aaa   -10
11  4   aar    10
12  4   rrp   -10

接下来我要做的是只获取在字符串列“name”中也具有最高相似性的匹配 pos 和 neg 数对。因此,如果一个 id 有两个与正 i 匹配的其他负数想隔离每个 id 相似度最高的对,所以我希望我想要的输出是这样的:

 id  name  amount
2   1   ada   12
3   1   ada   -12
4   2   dddd    5
5   2   fdd    -5
10  4   aaa   -10
11  4   aar    10

我想我必须使用某种类型的字符串相似性索引,如 sequencematcher 或 jaccard 等,但我不知道如何解决这个问题。非常感谢任何有关如何获得我想要的输出的帮助。

【问题讨论】:

  • 如果第一行是1 ada 12 需要输出两对 id=1 吗?
  • 对于 id=1 ,我只需要这一对,因为它具有最高的 str 相似性:2 1 ada 12 , 3 1 ada -12
  • 什么相似度法?提花?您希望输出看起来如何?
  • @Tomer S 是的 jaccard 很好。所需的输出在我的原始帖子(最后一个数据框)上。

标签: python python-3.x pandas string dataframe


【解决方案1】:

你可以试试这样的:

请注意,您可以根据需要更改打印的信息,只需编辑函数 create_sim 的返回值

import pandas as pd
from operator import itemgetter

d = {'id': [1,1,1,1,2,2,3,3,3,4,4,4,4],
     'name':['ada','aad','ada','ada','dddd','fdd','ccc','cccd','ood','aaa','aaa','aar','rrp']
    ,'amount':[2,-12,12,-12,5,-5,2,3,-5,3,-10,10,-10]}
df1 = pd.DataFrame(d)

def match_pos_neg(df):
    return df[df["amount"].isin(-df["amount"])]

df1 = df1.groupby("id").apply(match_pos_neg).reset_index(0, drop=True)

print(df1)


def split(word):
    return [char for char in word]


def DistJaccard(str1, str2):
    l1 = set(split(str1))
    l2 = set(split(str2))
    return float(len(l1 & l2)) / len(l1 | l2)


def create_sim(df, idx):
    idx_id = df['id'].values[idx]
    idx_amount = df['amount'].values[idx]
    idx_name = df['name'].values[idx]
    df_t = df.loc[df['id'] == idx_id]
    pos = [i for i in list(df_t['amount']) if i > 0] or None
    neg = [i for i in list(df_t['amount']) if i < 0] or None
    if pos and neg:
        l = [x for x in list(df_t['amount']) if x == idx_amount * -1]
        if len(l) > 0:
            df_t = df.loc[df['amount'] == idx_amount * -1]
            compare_list = list(df_t['name'])
            list_results = []
            for item in compare_list:
                sim = DistJaccard(idx_name, item)
                list_results.append((item, sim))
            return max(list_results, key=itemgetter(1))
    return None

count = 0
for index, row in df1.iterrows():
    res = create_sim(df1, count)
    if res:
        print(f"The most similar word of {row['name']} is {res[0]} with similarity of {res[1]}")
    else:
        print(f"No similar words of {row['name']}")
    count+=1

编辑:

为了使用结果制作 DF,您可以将其更改为:

count = 0
item1_id = []
item1_row = []
item1_name = []
item2_id = []
item2_row = []
item2_name = []
for index, row in df1.iterrows():
    res = create_sim(df1, count)
    item1_id.append(row['id'])
    item1_row.append(count)
    item1_name.append(row['name'])
    if res:
        row_idx = df1.loc[(df1['id'] == res[2]) & (df1['name'] == res[0]) & (df1['amount'] != row['amount']), "name"].index.tolist()
        item2_id.append(row['id'])
        item2_row.append(row_idx[0])
        item2_name.append(res[0])
    else:
        item2_id.append(None)
        item2_row.append(None)
        item2_name.append(None)
    count+=1


final = pd.DataFrame(item1_id, columns=['item 1 id'])
final['item 1 row'] = item1_row
final['item 1 name'] = item1_name
final['item 2 id'] = item2_id
final['item 2 row'] = item2_row
final['item 2 name'] = item2_name

print(final)

【讨论】:

  • 非常感谢您的努力!我怎样才能将相关行作为数据框而不是打印返回?就像在名称上具有最高相似性的相关正/负值对?
  • 查看编辑后的答案
  • 如果有帮助请点赞并接受
  • 您好,感谢您的帮助。也许我遗漏了一些东西,但“项目 1 id”不应该与“项目 2 id”在同一列中,并且与“项目 1 名称”和“项目 2 名称”等相同。现在,项目 2 列仅填充为 None。
  • 理想情况下,我希望 df 作为我想要的输出 df
猜你喜欢
  • 2018-06-11
  • 1970-01-01
  • 2011-12-10
  • 2011-08-17
  • 2013-02-24
  • 2011-04-04
  • 2016-07-15
  • 1970-01-01
  • 2012-01-27
相关资源
最近更新 更多