【问题标题】:Find levels of a factors that appear more than once查找多次出现的因子水平
【发布时间】:2013-05-23 05:35:08
【问题描述】:

我有这个数据框:

data <- data.frame(countries=c(rep('UK', 5),
                           rep('Netherlands 1a', 5),
                           rep('Netherlands', 5),
                           rep('USA', 5), 
                           rep('spain', 5), 
                           rep('Spain', 5),
                           rep('Spain 1a', 5),
                           rep('spain 1a', 5)),
               var=rnorm(40))

            countries          var
1              UK  0.506232270
2              UK  0.976348808
3              UK -0.752151769
4              UK  1.137267199
5              UK -0.363406715
6  Netherlands 1a -0.800835463
7  Netherlands 1a  1.767724231
8  Netherlands 1a  0.810757929
9  Netherlands 1a -1.188975114
10 Netherlands 1a -0.763144245
11    Netherlands  0.428511920
12    Netherlands  0.835184425
13    Netherlands -0.198316780
14    Netherlands  1.108191193
15    Netherlands  0.946819500
16            USA  0.226786121
17            USA -0.466886468
18            USA -2.217910876
19            USA -0.003472937
20            USA -0.784264921
21          spain -1.418014562
22          spain  1.002412706
23          spain  0.472621627
24          spain -1.378960222
25          spain -0.197020702
26          Spain  1.197971896
27          Spain  1.227648883
28          Spain -0.253083684
29          Spain -0.076562960
30          Spain  0.338882352
31       Spain 1a  0.074459521
32       Spain 1a -1.136391220
33       Spain 1a -1.648418916
34       Spain 1a  0.277264011
35       Spain 1a -0.568411569
36       spain 1a  0.250151646
37       spain 1a -1.527885883
38       spain 1a -0.452190849
39       spain 1a  0.454168927
40       spain 1a  0.889401396

我希望能够找到不止一次以不同形式出现的countries 级别。 countries 级别可能出现的表单有:

  1. 小写,例如“西班牙”
  2. 标题大写,例如“西班牙”
  3. 小写字母,附加不同的单词,例如“spain 1a”
  4. 附加了不同单词的标题,例如“Spain 1a”

所以我需要返回一个向量列表级别countries,它出现了不止一次。在data中,应该返回的向量是:

"Netherlands 1a", "Netherlands", "spain", "Spain", "spain 1a", "Spain 1a"

是否可以创建一个返回该向量的函数?

【问题讨论】:

  • 您可能想使用正则表达式来清理您的数据。请参阅。例如 ?grep?sub,并在在线教程中阅读正则表达式。
  • 国家名称是否包含空格?如果没有,您可以安全地丢弃第一个空格之后的字符串的任何部分。

标签: r dataframe r-factor


【解决方案1】:

应满足所有要求的快速解决方案(假设国家/地区名称始终是您的 data$country 条目的第一个元素):

# Country substrings
country.substr <- sapply(strsplit(tolower(levels(data$countries)), " "), "[[", 1)
# Duplicated country substrings
country.substr.dupl <- duplicated(country.substr)

# Display all country levels that appear in different forms
do.call("c", lapply(unique(country.substr[country.substr.dupl]), function(i) {
  levels(data$countries)[grep(i, tolower(levels(data$countries)))]
}))

[1] "Netherlands"    "Netherlands 1a" "spain"          "Spain"          "spain 1a"       "Spain 1a"

更新:

假设国家名称并不总是出现在第一个位置,您需要应用我从here 中采用的不同方法。请注意,我稍微修改了您的示例数据以澄清我在做什么:

data <- data.frame(countries=c(rep('United Kingdom', 5),
                               rep('united kingdom', 5),
                               rep('Netherlands', 5), 
                               rep('Netherlands 1a', 5),
                               rep('1a Netherlands', 5),
                               rep('USA', 5), 
                               rep('spain', 5), 
                               rep('Spain', 5),
                               rep('Spain 1a', 5),
                               rep('spain 1a', 5)),
                   var=rnorm(50))

现在让我们识别所有不包含任何数字的国家/地区子字符串。后续步骤保持不变。这是你需要的吗?

# Remove mixed numeric/alphabetic parts from country names
country.substr <- lapply(strsplit(tolower(levels(data$countries)), " "), function(i) {
  # Identify, paste and return alphabetic-only components
  tmp <- grep("^[[:alpha:]]*$", i)

  if (length(tmp) == 1)
    return(i[tmp])
  else
    return(paste(i[tmp], collapse = " ")) 
})

# Identify douplicated country names
country.substr.dupl <- duplicated(country.substr)

# Display all country levels that appear in different forms
do.call("c", lapply(unique(country.substr[country.substr.dupl]), function(i) {
  levels(data$countries)[grep(i, tolower(levels(data$countries)))]
}))

[1] "1a Netherlands" "Netherlands"    "Netherlands 1a" "spain"          "Spain"          "spain 1a"       "Spain 1a"       "united kingdom" "United Kingdom"

【讨论】:

  • 谢谢 - 这非常接近我的需要,但是有没有什么方法可以在不假设国家名称始终是第一个元素的情况下使功能正常工作?
  • 你的数据集中有没有1a以外的扩展名?
  • 是的,扩展名可能是,例如,2b 或 3c
  • 参见上面的编辑(仅当所述扩展始终包含至少一个数字组件时才有效)。干杯,
【解决方案2】:

为什么不使用grepignore.case 参数正是您所需要的。

> uch <- unique(as.character(data$countries))
> found <- sapply(seq(uch), function(i){
      if(!grepl("\\s|[0-9]", uch[i]))
          grep(uch[i], uch, ignore.case = TRUE, value = TRUE)
  })
> ff <- found[sapply(found, function(x) length(x) > 1)]
> unique(unlist(ff))
# [1] "Netherlands 1a" "Netherlands"    "spain" 
# [4] "Spain"          "Spain 1a"       "spain 1a"

这是我的逻辑:将列的唯一因子级别作为字符向量。然后,将其与自身进行比较,仅查看那些不包含空格或数字的级别。 grep 会抓住这些,但反过来会更难一些。然后,我们只找到唯一的匹配项。所以这里有一个函数和一个测试运行,

find.matches <- function(column)
{
    uch <- unique(as.character(column))
    found <- sapply(seq(uch), function(i){
        if(!grepl("\\s|[0-9]", uch[i]))
            grep(uch[i], uch, ignore.case = TRUE, value = TRUE)
        })
    ff <- found[sapply(found, function(x) length(x) > 1)]
    unique(unlist(ff))
}

> dat <- data.frame(x = c("a", "a1", "a 1b", "c", "d"),
                    y = c("fac", "tor", "fac 1a", "tor1a", "fac"))
> sapply(dat, find.matches)
# $x
# [1] "a"    "a1"   "a 1b"
# 
# $y
# [1] "fac"    "fac 1a" "tor"    "tor1a" 

【讨论】:

    猜你喜欢
    • 2020-11-13
    • 2017-01-02
    • 1970-01-01
    • 1970-01-01
    • 2015-04-04
    • 1970-01-01
    • 1970-01-01
    • 2019-08-26
    • 1970-01-01
    相关资源
    最近更新 更多