【问题标题】:Data Cleaning in R: remove test customer namesR中的数据清理:删除测试客户名称
【发布时间】:2018-01-04 05:16:15
【问题描述】:

我正在处理包含客户名字和姓氏的客户数据。我想清除任何随机击键的名称。测试帐户在数据集中杂乱无章,并且具有垃圾名称。例如,在下面的数据中,我想删除客户 2、5、9、10、12 等。感谢您的帮助。

 Customer Id    FirstName   LastName
1   MARY    MEYER
2   GFRTYUIO    UHBVYY
3   CHARLES BEAL
4   MARNI   MONTANEZ
5   GDTDTTD DTTHDTHTHTHD
6   TIFFANY BAYLESS
7   CATHRYN JONES
8   TINA    CUNNINGHAM
9   FGCYFCGCGFC FGCGFCHGHG
10  ADDHJSDLG   DHGAHG
11  WALTER  FINN
12  GFCTFCGCFGC CG GFCGFCGFCGF
13  ASDASDASD   AASDASDASD
14  TYKTYKYTKTY YTKTYKTYK
15  HFHFHF  HAVE
16  REBECCA CROSSWHITE
17  GHSGHG  HGASGH
18  JESSICA TREMBLEY
19  GFRTYUIO    UHBVYY
20  HUBHGBUHBUH YTVYVFYVYFFV
21  HEATHER WYRICK
22  JASON   SPLICHAL
23  RUSTY   OWENS
24  DUSTIN  WILLIAMS
25  GFCGFCFGCGFC    GRCGFXFGDGF
26  QWQWQW  QWQWWW
27  LIWNDVLIHWDV    LIAENVLIHEAV
28  DARLENE SHORTRIDGE
29  BETH    HDHDHDH
30  ROBERT  SHIELDS
31  GHERDHBXFH  DFHFDHDFH
32  ACE TESSSSSRT
33  ALLISON AWTREY
34  UYGUGVHGVGHVG   HGHGVUYYU
35  HCJHV   FHJSEFHSIEHF

【问题讨论】:

  • “随机击键”的规则是什么?
  • 恐怕没有规矩。测试帐户是通过随机敲击名字和姓氏的键盘键来创建的。如果有一个模式,那就太容易了。感谢您的澄清。
  • 首先使用hunspell 库:library(hunspell); df$flag <- hunspell_check(df$FirstName) & hunspell_check(df$LastName) 尽管它并不完美(这就是我创建标志的原因)。我认为如果一个名字没有被标记,那么你可以确定它是有效的。但是,您有像第 4 行“Marni Montanez”这样的案例,它似乎有效但已被标记。
  • 那么您的目标是找到一个名称数据库(最常见的?)并根据它对您的数据进行子集化。在 R 中相对容易。但是,找到这样的数据库超出了 SO 的范围。
  • 谢谢迈克!我认为这可能是一个很好的开始,我会检查 hunspell 的更多功能。谢谢

标签: r data-cleaning


【解决方案1】:

问题似乎是您需要对不太可能的名称进行可靠的定义,而这与 R 并没有真正的关系。无论如何,我建议您按名字来并删除所有那些不合理的名称。作为合理的名字或肯定列表的来源,您可以使用例如SSA Baby Name Database。这应该可以很好地过滤掉英文名字。如果您对名字有更多特定位置的需求,只需在线查找其他婴儿姓名数据库并尝试将它们作为肯定列表。

将它们放入名为 positiveNames 的向量中后,过滤掉所有非正数名称,如下所示:

data_new <- data_original[!data_original$firstName %in% positiveNames,]

【讨论】:

  • 我尝试了类似的方法并使用了 SSA 数据库,通过清理发出它。我的数据集有来自世界各地的名称。这可能不是特定于 R 的,但在宏观意义上,我正在寻找一种可以识别不可能名称的逻辑。使用 SSA,一半的名称被标记为非阳性。
【解决方案2】:

我的方法如下:

1) 将FirstNameLastName 合并为一个字符串strname。 然后,计算每个strname 的字母数。

2)此时,我们发现对于真名,如“MARNIMONTANEZ”,由两个“M”组成;两个'A';一个“R”;一个“我”;三个“N”;一个“O”;一个“T”。
我们发现假名字,比如“GFCTFCGCFGCCGGFCGFCGFCGF”,是由六个“G”组成的;五个“F”; 8'C'。

3) 区分真名和假名的模式变得清晰:

  • 真实姓名的特征在于更多种类的字母。我们可以通过创建变量check_real 来衡量这一点,计算方式为:number of unique letters / total string length
  • 假名的特点是几个字母重复多次。我们可以通过创建变量check_fake 来衡量这一点,计算方式为:average frequency of each letter

4) 最后,我们只需要定义一个阈值来识别两个变量的异常。在触发这些阈值的情况下,会出现flag_realflag_fake

  • 如果flag_real == 1 &amp; flag_fake == 0,名字是真实的
  • 如果flag_real == 0 &amp; flag_fake == 1,名字是假的
  • 在两个标志一致的极少数情况下(即flag_real == 1 &amp; flag_fake == 1),您必须手动调查记录以优化阈值。

【讨论】:

  • 这太棒了。我希望能在这些线上找到一些东西。让我试一试。我想这里的关键是找到一个正确的阈值。我会更新我的发现。谢谢。
  • 请注意,check_real 和 check_fake 变量只是两个示例,我相信我们可以生成更有意义或有区别的变量来表示名称是真还是假。此外,由于现在我们处于大数据世界,更好的方法可以将我的想法与 @tophcito 的想法结合起来,将您的数据与外部开放数据源集成。
【解决方案3】:

您可以通过计算全名中唯一字母的长度除以全名中的字符总数来计算全名的可变性强度(结合名字和姓氏)。然后,只需删除具有低可变性强度的名称。这意味着您要删除相同随机击键频率较高的名称,从而导致可变性强度较低。​​

我使用charToRaw 函数来完成此操作,因为它非常快并且使用dplyr 库,如下所示:

# Building Test Data
df <- data.frame(CustomerId = c(1, 2, 3, 4, 5, 6, 7), 
          FirstName = c("MARY", "FGCYFCGCGFC", "GFCTFCGCFGC", "ASDASDASD", "GDTDTTD", "WALTER", "GFCTFCGCFGC"),
          LastName = c("MEYER", "FGCGFCHGHG", "GFCGFCGFCGF", "AASDASDASD", "DTTHDTHTHTHD", "FINN", "CG GFCGFCGFCGF"), stringsAsFactors = FALSE)


#test data: df
#   CustomerId    FirstName         LastName
#1         1           MARY            MEYER
#2         2    FGCYFCGCGFC       FGCGFCHGHG
#3         3    GFCTFCGCFGC      GFCGFCGFCGF
#4         4      ASDASDASD       AASDASDASD
#5         5        GDTDTTD     DTTHDTHTHTHD
#6         6         WALTER             FINN
#7         7    GFCTFCGCFGC   CG GFCGFCGFCGF

library(dplyr)
df %>%
  ## Combining FirstName and LastName
  mutate(FullName = paste(FirstName, gsub(" ", "", LastName, fixed = TRUE))) %>%
  group_by(FullName) %>%
  ## Calculating variability strength for each full name
  mutate(Variability = length(unique(as.integer(charToRaw(FullName))))/nchar(FullName))%>%
  ## Filtering full name, I set above or equal to 0.4 (You can change this)
  ## Meaning we are keeping full name that has variability strength greater than or equal to 0.40
  filter(Variability >= 0.40)


# A tibble: 2 x 5
# Groups:   FullName [2]
# CustomerId FirstName LastName    FullName   Variability
#  <dbl>     <chr>      <chr>        <chr>        <dbl>
#1   1        MARY      MEYER     MARY MEYER    0.6000000
#2   6      WALTER      FINN     WALTER FINN    0.9090909

【讨论】:

  • 在计算可变性时你不是在FullName 中包含空格吗?
  • 是的,但是每个全名都有一个空格。所以,总的来说,这并不重要。
  • 检查 OP 示例中的第 12 行 - 如果随机击键是空格怎么办?
  • 谢谢,我使用gsub 删除了姓氏中的空格。我还在测试数据中添加了第 12 行示例。
  • @Santosh 感谢您编写我的答案代码。但是,缺少一个关键组成部分,即“strname”中字母的平均频率。这一点非常重要,因为它可以进行更精细和可靠的异常检测,尤其是它突出了极少数模棱两可且需要进行人工调查的案例。谢谢
【解决方案4】:

我尝试结合以下代码中的建议。感谢大家的帮助。

# load required libraries 
library(hunspell)
library(dplyr)
# read data in dataframe df
df<-data.frame(CustomerId = c(1, 2, 3, 4, 5, 6, 7,8), 
               FirstName = c("MARY"," ALBERT SAM", "FGCYFCGCGFC", "GFCTFCGCFGC", "ASDASDASD", "GDTDTTD", "WALTER", "GFCTFCGCFGC"),
               LastName = c("MEYER","TEST", "FGCGFCHGHG", "GFCGFCGFCGF", "AASDASDASD", "DTTHDTHTHTHD", "FINN", "CG GFCGFCGFCGF"), stringsAsFactors = FALSE)
# Keep unique names
df<-distinct(df,FirstName, LastName, .keep_all = TRUE)
# Spell check using hunspel
df$flag <- hunspell_check(df$FirstName) | hunspell_check(as.character(df$LastName))
# remove middle names
df$FirstNameOnly<-gsub(" .*","",df$FirstName)

# SSA name data using https://www.ssa.gov/oact/babynames/names.zip
# unzip files in folder named names
files<-list.files("/names",pattern="*.txt")
ssa_names<- do.call(rbind, lapply(files, function(x) read.csv(x, 
                          col.names = c("Name","Gender","Frequency"),stringsAsFactors = FALSE)))
# Change SSA names to uppercase
ssa_names$Name <- toupper(ssa_names$Name)
# Flad for SSA names
df$flag_SSA<-ifelse(df$FirstNameOnly %in% ssa_names$Name,TRUE,FALSE)
rm(ssa_names)
# remove spaces and concatenate first name and last name
df$strname<-gsub(" ","",paste(df$FirstName,df$LastName, sep = ""))
# Name string length
df$len<-nchar(df$strname)

# Unique string length
for(n in 1:nrow(df))
{
  df$ulen[n]<-length(unique(strsplit(df$strname[n], "")[[1]]))
}

# Ratio variable for unique string length over total string length 
df$ratio<-ifelse(df$len==0,0,df$ulen/df$len)
# Histogram to determine cutoff ratio
hist(df$ratio)
test<-df[df$ratio<.4 & df$flag_SSA==FALSE & df$flag==FALSE,]

【讨论】:

    猜你喜欢
    • 2015-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-11
    • 2020-02-04
    • 2012-12-13
    • 2018-12-25
    相关资源
    最近更新 更多