我正在尝试构建一个Python模型,用于将账户名称分类为合法或无意义。在这种特定情况下,字母的大小写并不重要,因为一些合法的账户名称可能全部由大写或小写字母组成。
免责声明:这仅是内部研究/实验,不会根据分类结果采取任何实际行动。
在我特定的情况下,有两种可能的特征可以揭示账户名称为可疑、无意义或两者兼有:
-
名称中包含奇怪/随机的拼写,或者名称纯粹或主要由数字组成。符合这些标准的账户名称示例包括:128, 127, h4rugz4sx383a6n64hpo, tt, t66, t65, asdfds。
-
名称有两个组成部分(假设名称永远不会超过两个组成部分),且这两个组成部分的拼写和发音非常相似。符合这些标准的账户名称示例包括:Jala Haja, Hata Yaha, Faja Kaja。
如果一个账户名称同时满足上述两个标准(例如 ‘asdfs lsdfs’, ‘332 333’),也应被视为可疑。
另一方面,合法的账户名称不需要同时包含名字和姓氏。它们通常是来自流行语言的名称,例如罗马/拉丁语系(如西班牙语、德语、葡萄牙语、法语、英语)、中文和日文。
合法的账户名称示例包括(这些名称是虚构的,但确实反映了现实世界中合法账户名称的类似风格):Michael, sara, jose colmenares, Dimitar, Jose Rafael, Morgan, Eduardo Medina, Luis R. Mendez, Hikaru, SELENIA, Zhang Ming, Xuting Liu, Chen Zheng。
我在Stackoverflow上看到了一些稍微相似的问题,这些问题询问如何检测无意义文本。但那些问题不适合我的情况,因为合法的文本和单词实际上是有意义的,而人的名字通常没有意义。我还希望仅基于账户名称来实现这一点,而不依赖其他信息。
目前,我的脚本负责查找可疑账户名称的第二种特征(名称中相似的组成部分),使用Python的Fuzzy Wuzzy包,并以50%作为相似度阈值。脚本如下所示:
from fuzzywuzzy import fuzzfrom fuzzywuzzy import processimport pandas as pdimport numpy as npaccounts = pd.read_csv('dataset_with_names.csv', encoding = 'ISO-8859-1', sep=None, engine='python').replace(np.nan, 'blank', regex=True)pd.options.mode.chained_assignment = Noneaccounts.columns = ['name', 'email', 'akon_id', 'acct_creation_date', 'first_time_city', 'first_time_ip', 'label']accounts['name_simplified']=accounts['name'].str.replace('[^\w\s]','')accounts['name_simplified']=accounts['name_simplified'].str.lower()sim_name = []for index, row in accounts.iterrows(): if ' ' in row['name_simplified']: row['name_simplified']=row['name_simplified'].split() if len(row['name_simplified']) > 1: #print(row['name_simplified']) if fuzz.ratio(row['name_simplified'][0], row['name_simplified'][1]) >= 50: sim_name.append('True') else: sim_name.append('False') else: sim_name.append('False') else: sim_name.append('False') accounts['are_name_components_similar'] = sim_name
该结果对于脚本设计的功能来说是可靠的,但我还希望能够识别出符合第一种特征(奇怪/随机拼写或名称纯粹或主要由数字组成)的无意义账户名称。到目前为止,我还没有找到解决方案。
有谁能帮忙吗?任何反馈/建议将不胜感激!
回答:
对于第一种特征,您可以训练一个基于字符的n-gram语言模型,并将所有平均每个字符概率低的名称视为可疑。
下面是一个快速而粗糙的语言模型示例。这是一个由1-gram、2-gram和3-gram语言模型混合而成的模型,训练于布朗语料库。我相信您可以找到更相关的训练数据(例如,所有演员的名字列表)。
from nltk.corpus import brownfrom collections import Counterimport numpy as nptext = '\n '.join([' '.join([w for w in s]) for s in brown.sents()])unigrams = Counter(text)bigrams = Counter(text[i:(i+2)] for i in range(len(text)-2))trigrams = Counter(text[i:(i+3)] for i in range(len(text)-3))weights = [0.001, 0.01, 0.989]def strangeness(text): r = 0 text = ' ' + text + '\n' for i in range(2, len(text)): char = text[i] context1 = text[(i-1):i] context2 = text[(i-2):i] num = unigrams[char] * weights[0] + bigrams[context1+char] * weights[1] + trigrams[context2+char] * weights[2] den = sum(unigrams.values()) * weights[0] + unigrams[context1] * weights[1] + bigrams[context2] * weights[2] r -= np.log(num / den) return r / (len(text) - 2)
现在您可以将此“怪异度”测量应用于您的示例。
t1 = '128, 127, h4rugz4sx383a6n64hpo, tt, t66, t65, asdfds'.split(', ')t2 = 'Michael, sara, jose colmenares, Dimitar, Jose Rafael, Morgan, Eduardo Medina, Luis R. Mendez, Hikaru, SELENIA, Zhang Ming, Xuting Liu, Chen Zheng'.split(', ')for t in t1 + t2: print('{:20} -> {:9.5}'.format(t, strangeness(t)))
您会发现无意义的名称在大多数情况下比正常名称更“怪异”。您可以在这里使用例如3.9作为阈值。
128 -> 5.5528127 -> 5.6572h4rugz4sx383a6n64hpo -> 5.9016tt -> 4.9392t66 -> 6.9673t65 -> 6.8501asdfds -> 3.9776Michael -> 3.3598sara -> 3.8171jose colmenares -> 2.9539Dimitar -> 3.4602Jose Rafael -> 3.4604Morgan -> 3.3628Eduardo Medina -> 3.2586Luis R. Mendez -> 3.566Hikaru -> 3.8936SELENIA -> 6.1829Zhang Ming -> 3.4809Xuting Liu -> 3.7161Chen Zheng -> 3.6212
当然,一个更简单的解决方案是收集您目标语言中所有流行名称的列表,完全不使用机器学习 – 只进行查找。