无法使用 Python 检测乱码名称
Unable to detect gibberish names using Python
我正在尝试构建 Python 模型,该模型可以将帐户名称分类为合法或乱码。在这种特殊情况下,大小写并不重要,因为一些合法的帐户名称可能由全部大写或全部小写字母组成。
免责声明:这只是内部 research/experiment,不会对分类器结果采取任何实际行动。
就我而言,有 2 个可能的特征可以将帐户名称显示为可疑、乱码或两者兼而有之:
Weird/random 名称或名称的拼写完全或主要由数字组成。符合这些条件的帐户名称示例是:128、127、h4rugz4sx383a6n64hpo、tt、t66、t65、asdfds.
名字有 2 个组成部分(假设没有一个名字有超过 2 个组成部分)并且这 2 个组成部分的拼写和发音非常相似。符合这些条件的帐户名称示例有:Jala Haja、Hata Yaha、Faja Kaja.
如果一个账户名符合上述两个标准(即'asdfs lsdfs','332 333'),它也应该被认为是可疑的。
另一方面,合法的帐户名不需要同时包含名字和姓氏。它们通常是流行语言的名称,例如 Roman/Latin(即西班牙语、德语、葡萄牙语、法语、英语)、中文和日语。
合法帐户名称的示例包括(这些名称是虚构的,但确实反映了现实世界中合法帐户名称的相似样式):Michael、sara、jose colmenares、Dimitar、Jose Rafael、Morgan、 Eduardo Medina, Luis R. Mendez, Hikaru, SELENIA, Zhang Ming, Xuting Liu, Chen Zheng.
我在 Whosebug 上看到了一些稍微类似的问题,询问如何检测乱码文本。但是那些不适合我的情况,因为合法的文本和单词实际上是有意义的,而人名通常没有。我还希望能够仅根据帐户名称而不是其他任何内容来完成此操作。
现在我的脚本负责使用 Python 的 Fuzzy Wuzzy 包并使用 50% 作为相似度阈值来查找可疑帐户名称的第二个特征(名称中的相似组件)。脚本如下:
from fuzzywuzzy import fuzz
from fuzzywuzzy import process
import pandas as pd
import numpy as np
accounts = 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 = None
accounts.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
结果对于脚本的设计目的来说是可靠的,但我也希望能够显示具有第一个特征的乱码帐户名称(weird/random 拼写或名称完全或主要由数字组成).到目前为止,我还没有找到解决方案。
有人可以帮忙吗?任何 feedback/suggestion 将不胜感激!
对于第一个特征,您可以训练一个基于字符的 n-gram 语言模型,并将所有平均每个字符概率较低的名称视为可疑。
下面是这种语言模型的简单示例。它是 1-gram、2-gram 和 3-gram 语言模型的混合体,在 Brown 语料库上训练。我相信您可以找到更多相关的训练数据(例如所有演员的名单)。
from nltk.corpus import brown
from collections import Counter
import numpy as np
text = '\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.5528
127 -> 5.6572
h4rugz4sx383a6n64hpo -> 5.9016
tt -> 4.9392
t66 -> 6.9673
t65 -> 6.8501
asdfds -> 3.9776
Michael -> 3.3598
sara -> 3.8171
jose colmenares -> 2.9539
Dimitar -> 3.4602
Jose Rafael -> 3.4604
Morgan -> 3.3628
Eduardo Medina -> 3.2586
Luis R. Mendez -> 3.566
Hikaru -> 3.8936
SELENIA -> 6.1829
Zhang Ming -> 3.4809
Xuting Liu -> 3.7161
Chen Zheng -> 3.6212
当然,一个更简单的解决方案是收集所有目标语言中的流行名字列表,并且根本不使用机器学习——只是查找。
我正在尝试构建 Python 模型,该模型可以将帐户名称分类为合法或乱码。在这种特殊情况下,大小写并不重要,因为一些合法的帐户名称可能由全部大写或全部小写字母组成。
免责声明:这只是内部 research/experiment,不会对分类器结果采取任何实际行动。
就我而言,有 2 个可能的特征可以将帐户名称显示为可疑、乱码或两者兼而有之:
Weird/random 名称或名称的拼写完全或主要由数字组成。符合这些条件的帐户名称示例是:128、127、h4rugz4sx383a6n64hpo、tt、t66、t65、asdfds.
名字有 2 个组成部分(假设没有一个名字有超过 2 个组成部分)并且这 2 个组成部分的拼写和发音非常相似。符合这些条件的帐户名称示例有:Jala Haja、Hata Yaha、Faja Kaja.
如果一个账户名符合上述两个标准(即'asdfs lsdfs','332 333'),它也应该被认为是可疑的。
另一方面,合法的帐户名不需要同时包含名字和姓氏。它们通常是流行语言的名称,例如 Roman/Latin(即西班牙语、德语、葡萄牙语、法语、英语)、中文和日语。
合法帐户名称的示例包括(这些名称是虚构的,但确实反映了现实世界中合法帐户名称的相似样式):Michael、sara、jose colmenares、Dimitar、Jose Rafael、Morgan、 Eduardo Medina, Luis R. Mendez, Hikaru, SELENIA, Zhang Ming, Xuting Liu, Chen Zheng.
我在 Whosebug 上看到了一些稍微类似的问题,询问如何检测乱码文本。但是那些不适合我的情况,因为合法的文本和单词实际上是有意义的,而人名通常没有。我还希望能够仅根据帐户名称而不是其他任何内容来完成此操作。
现在我的脚本负责使用 Python 的 Fuzzy Wuzzy 包并使用 50% 作为相似度阈值来查找可疑帐户名称的第二个特征(名称中的相似组件)。脚本如下:
from fuzzywuzzy import fuzz
from fuzzywuzzy import process
import pandas as pd
import numpy as np
accounts = 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 = None
accounts.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
结果对于脚本的设计目的来说是可靠的,但我也希望能够显示具有第一个特征的乱码帐户名称(weird/random 拼写或名称完全或主要由数字组成).到目前为止,我还没有找到解决方案。
有人可以帮忙吗?任何 feedback/suggestion 将不胜感激!
对于第一个特征,您可以训练一个基于字符的 n-gram 语言模型,并将所有平均每个字符概率较低的名称视为可疑。
下面是这种语言模型的简单示例。它是 1-gram、2-gram 和 3-gram 语言模型的混合体,在 Brown 语料库上训练。我相信您可以找到更多相关的训练数据(例如所有演员的名单)。
from nltk.corpus import brown
from collections import Counter
import numpy as np
text = '\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.5528
127 -> 5.6572
h4rugz4sx383a6n64hpo -> 5.9016
tt -> 4.9392
t66 -> 6.9673
t65 -> 6.8501
asdfds -> 3.9776
Michael -> 3.3598
sara -> 3.8171
jose colmenares -> 2.9539
Dimitar -> 3.4602
Jose Rafael -> 3.4604
Morgan -> 3.3628
Eduardo Medina -> 3.2586
Luis R. Mendez -> 3.566
Hikaru -> 3.8936
SELENIA -> 6.1829
Zhang Ming -> 3.4809
Xuting Liu -> 3.7161
Chen Zheng -> 3.6212
当然,一个更简单的解决方案是收集所有目标语言中的流行名字列表,并且根本不使用机器学习——只是查找。