【问题标题】:R modify value in one column if content in another column contains string如果另一列中的内容包含字符串,则R修改一列中的值
【发布时间】:2018-05-21 01:33:30
【问题描述】:

我正在处理一个大型数据集,我想确定包含文本字符串的列是否通过了逻辑测试,我可以稍后将其子集化。目前,我正在尝试为每一行构建测试列。测试基于单元格是否包含少于 2 个相关字符,但我想将完整的字符集保留在实际单元格中。以下是我正在尝试做的一个简化示例:

假设我有以下数据框:

df <- data.frame(matrix(NA, nrow = 5, ncol = 1))
colnames(df) <- "test"
df$test <- c("one", "two", "three", "one", "onetwo")
df$hyp <- ("two", "one", "onetwo", "one", "two")
df$testcount <- sapply(df$test, str_length)
df$hypcount <- sapply(df$hyp, str_length)
df

    test    hyp testcount hypcount
1    one    two         3        3
2    two    one         3        3
3  three onetwo         5        6
4    one    one         3        3
5 onetwo    two         6        3

我想识别一个文本字符串,例如“two”,以及 test 列或 hyp 列中的一行(取决于我正在运行的测试。我不希望它继续运行两列)包含字符串(尽管与字符串不同),然后我希望同一行从testcounthypcount 列中减去我标识的字符串中的字符数。

例如,如果我对test 列中的文本字符串“two”运行此函数,那么我应该得到以下输出:

    test    hyp testcount hypcount
1    one    two         3        3
2    two    one         0        3
3  three onetwo         5        6
4    one    one         3        3
5 onetwo    two         3        3

如果我要在 hyp 列上运行它,那么我应该得到以下输出:

    test    hyp testcount hypcount
1    one    two         3        0
2    two    one         3        3
3  three onetwo         5        3
4    one    one         3        3
5 onetwo    two         6        0

我尝试了三种方法。首先,我尝试使用 if 函数有条件地运行替换(在此测试中,我测试了字符串“one”而不是“two”):

if(grepl("one", df$test)) {
  df[which(grepl("one", df$test)), ]$testcount = df[which(grepl("one", df$test)), ]$testcount - 3
  }

但这会返回警告: “在 if (grepl("one", df$test)) { : 条件的长度 > 1 并且只使用第一个元素"

这会导致正确替换字符串“one”,而不是字符串“two”。此外,如果我在hyp 列中替换字符串“two”,则该函数可以工作,但如果我运行字符串“one”的替换,则不会。我怀疑这是因为它只在第一行运行测试,如果它是真的,那么它会检查整个数据框。

接下来我尝试在 lapply 函数中运行该函数:

df <- data.frame(lapply(df, function(x) {
  if(grepl("one", df$test)) {
    df[which(grepl("one", df$test)), ]$testcount = df[which(grepl("one", df$test)), ]$testcount - 3
  }}))

这也不起作用,虽然我不完全明白为什么。不知何故,它最终返回了输出:

  test hyp testcount hypcount
1    0   0         0        0
2    0   0         0        0
3    3   3         3        3

最后,我尝试将它作为 ifelse 操作运行(这里我切换到替换字符串“two”,所以我不会错误地认为该函数适用于所有行):

df$testcount <- ifelse(grepl("two", df$test), (df[which(grepl("two", df$test)), ]$testcount = df[which(grepl("two", df$test)), ]$testcount - 3))

奇怪的是,当我几天前第一次应用它时,它就起作用了。我对字符串“two”、“on”和“one”进行了测试,它工作正常。现在,当我开始将其应用于我的实际数据时,它不起作用。此外,当我回到测试中查看出了什么问题时,它不再起作用了。它只是返回错误: “ifelse(grepl("two", df$test), (df[which(grepl("two", df$test))), 中的错误: 缺少参数“no”,没有默认值”

我已经尝试了两种解决方案。首先,我尝试在“否”参数中添加一个不会影响我的数据的语句:

 df$testcount <- ifelse(grepl("two", df$test), (df[which(grepl("two", df$test)), ]$testcount = df[which(grepl("two", df$test)), ]$testcount - 3), T)

但是,这会导致它返回输出:

    test    hyp testcount hypcount
1    one    two         1        3
2    two    one         3        3
3  three onetwo         1        6
4    one    one         1        3
5 onetwo    two         0        3

接下来我尝试替换一个有意义的“否”论点:

 df$testcount <- ifelse(grepl("two", df$test), (df[which(grepl("two", df$test)), ]$testcount = df[which(grepl("two", df$test)), ]$testcount - 3), (df[which(grepl("two", df$test)), ]$testcount = df[which(grepl("two", df$test)), ]$testcount))

但现在它返回输出:

    test    hyp testcount hypcount
1    one    two        -3        3
2    two    one         0        3
3  three onetwo        -3        6
4    one    one         0        3
5 onetwo    two        -3        3

我不明白这个输出。

我的问题是,谁能帮助我理解为什么这不起作用并提供解决方案?提前致谢!

【问题讨论】:

  • “我希望同一行减去我识别的字符串中的字符数”。在您的第一个示例中,onetwo 包含字符串 two,因此您不应该从 testcount = 6 中减去 6(onetwo 的长度)以获得零吗?
  • 好的,我从您下面的评论中看到“字符串”是匹配字符串(两个),而不是匹配字符串(一个两个)。

标签: r


【解决方案1】:

试试这个功能:

subtract_match <- function(column1, column2, text, df) {
  df2 <- df
  df2[, column2] <- ifelse(grepl(text, df[, column1]), 
                           df[, column2] - nchar(text), 
                           df[, column2])
  df2
}

subtract_match("test", "testcount", "two", df1)

    test    hyp testcount hypcount
1    one    two         3        3
2    two    one         0        3
3  three onetwo         5        6
4    one    one         3        3
5 onetwo    two         3        3

subtract_match("hyp", "hypcount", "two", df1)

    test    hyp testcount hypcount
1    one    two         3        0
2    two    one         3        3
3  three onetwo         5        3
4    one    one         3        3
5 onetwo    two         6        0

【讨论】:

  • 这成功了!非常感谢。此外,我可以抽出函数的核心,它应该运行得更快,因为它不再是函数调用。 df$testcount &lt;- ifelse(grepl("two", df$test), df$testcount - nchar("two"), df$testcount) 很有趣,我的第三种方法非常接近解决方案...再次感谢!
【解决方案2】:

我不确定我是否完全理解您的问题,但以下内容重现了您对两个测试用例的预期结果。

# The first argument is the column where you want to find id
# I'm unsure about what you want to subtract; subtracting the entry from 
# the count columns corresponds to setting the entry to 0
some_function <- function(col, id, df) {
    idx <- which(colnames(df) == col);
    df[df[, idx] == id, idx + 2] <- 0;
    return(df);
}

some_function("test", "two", df);
#    test    hyp testcount hypcount
#1    one    two         3        3
#2    two    one         0        3
#3  three onetwo         5        6
#4    one    one         3        3
#5 onetwo    two         6        3

some_function("hyp", "two", df)
#    test    hyp testcount hypcount
#1    one    two         3        0
#2    two    one         3        3
#3  three onetwo         5        6
#4    one    one         3        3
#5 onetwo    two         6        0

另外,您说 “包含字符串(尽管与字符串不同)”,但对于包含“onetwo”的条目,您会 not 减去计数值.所以你追求的是完整的比赛吗?

【讨论】:

  • 抱歉,此函数无法识别字符串“two”在test 列的第五行,并将testcount 列的第五行的值更改为3。目标是识别test 列中文本字符串的所有实例,并从testcount 列中的值中减去该文本字符串的长度(在字符串“二”的情况下为三个)字符串。这有帮助吗?
猜你喜欢
  • 2019-02-18
  • 2021-10-05
  • 1970-01-01
  • 2018-12-05
  • 2015-08-19
  • 2022-11-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多