【问题标题】:Does part of one column exist in another? R一列的一部分是否存在于另一列中? R
【发布时间】:2021-08-07 22:17:53
【问题描述】:

我有这个数据框:

df <- data.frame(id_1=c('888046309', '888046309', '888046309', '888046309', '003046309', '465798132', '465798132', '465798132', '465798132', '465798132', '465798132', '465798132', '465798132'), 
                 id_2=c('0003046309', '0003046309', '0003046309', '0003046309', '0003046309', '0003046309', '0003046309', '0003046309', '0003046309', '0003046309', '0003046309', '0003046309', '0003046309'))

我想创建一个列来指示id_2一部分id_1 中的位置。

我从这个suggestion尝试过这个

i <- sapply(seq_along(df$id_2), function(i) grepl(df$id_2[i], df$id_1[i]))

df$flag <- c("No", "Yes")[i + 1L]

尽管您可以看到 id_1id_2 中都存在 46309,但 flag 具有所有 NO 值。

然后我从这个suggestion尝试了这个

df$flag_2 <- str_detect(df$id_1, df$id_2)

我得到了flag_2 的错误

最后我尝试了这个,就像flag_2一样,我得到了flag_3的所有错误。

df <- df %>% 
    mutate(flag_3 = c('No', 'Yes')[1+str_detect(id_1, as.character(id_2))])

是否可以编辑这些建议以指示id_2 的某些部分是否存在于id_1 中?

【问题讨论】:

  • 也许this 有帮助
  • 此建议末尾列出的函数仅允许前导数字相同的情况。非常感谢,但它没有用。
  • 所以,为了清楚起见,仍然需要将 1 个字符重叠标记为“是”?
  • 好问题。四个或更多怎么样?
  • 这个答案似乎对您的问题有效,尽管您需要添加nchar( ) &gt;= 4:stackoverflow.com/a/48702045/5805670

标签: r dataframe


【解决方案1】:

您可以使用adist,它基本上计算将一个字符串转换为另一个字符串的成本。定义一个threshold 您希望允许多少替换并设置相应的标志。

df$d <- t(apply(df[c('id_1', 'id_2')], 1, adist))[,2]
df
#         id_1       id_2 d
# 1  888046309 0003046309 4
# 2  888046309 0003046309 4
# 3  888046309 0003046309 4
# 4  888046309 0003046309 4
# 5  003046309 0003046309 1
# 6  465798132 0003046309 9
# 7  465798132 0003046309 9
# 8  465798132 0003046309 9
# 9  465798132 0003046309 9
# 10 465798132 0003046309 9
# 11 465798132 0003046309 9
# 12 465798132 0003046309 9
# 13 465798132 0003046309 9

th <- nchar(df$id_2)[1] - 2
df$flag <- with(df, ifelse(d > th, 1, 0))
df
#         id_1       id_2 d flag
# 1  888046309 0003046309 4    0
# 2  888046309 0003046309 4    0
# 3  888046309 0003046309 4    0
# 4  888046309 0003046309 4    0
# 5  003046309 0003046309 1    0
# 6  465798132 0003046309 9    1
# 7  465798132 0003046309 9    1
# 8  465798132 0003046309 9    1
# 9  465798132 0003046309 9    1
# 10 465798132 0003046309 9    1
# 11 465798132 0003046309 9    1
# 12 465798132 0003046309 9    1
# 13 465798132 0003046309 9    1

结合

我们当然可以将这两个步骤结合起来,那么它看起来像这样:

th <- 8  ## arbitrary
df <- within(df, flag <- t(apply(df[c('id_1', 'id_2')], 1, adist))[,2] < th)
df
#         id_1       id_2  flag
# 1  888046309 0003046309  TRUE
# 2  888046309 0003046309  TRUE
# 3  888046309 0003046309  TRUE
# 4  888046309 0003046309  TRUE
# 5  003046309 0003046309  TRUE
# 6  465798132 0003046309 FALSE
# 7  465798132 0003046309 FALSE
# 8  465798132 0003046309 FALSE
# 9  465798132 0003046309 FALSE
# 10 465798132 0003046309 FALSE
# 11 465798132 0003046309 FALSE
# 12 465798132 0003046309 FALSE
# 13 465798132 0003046309 FALSE

【讨论】:

  • 谢谢@jay.sf 我的真实数据集在第 7 列和第 8 列有这两个变量。如果我要采用这个解决方案,我会用 8 替换 1 w 7 和 2 吗?我试过了,得到了这个错误 'MARGIN' does not match dim(X) with the d variable
  • @tangerine7199 使用两个列名作为apply 中的子集,请参阅更新。
  • 太棒了!谢谢!
  • @tangerine7199 你可以将它组合成一个单行,查看更新。
【解决方案2】:

我不确定这是否是您的想法,我尝试过并取得了一些令人鼓舞的结果,但仍有改进的余地。为此,我从id_2 中删除了 2 个0,这可能不是一个好的调用,但它有助于在这里进行模糊匹配。

df$flag <- sapply(1:nrow(df), function(x) agrepl(substr(df$id_2[x], 2, nchar(df$id_2[x])), 
                                                 df$id_1[x], max.distance = 4))


df

        id_1       id_2  flag
1  888046309 0003046309  TRUE
2  888046309 0003046309  TRUE
3  888046309 0003046309  TRUE
4  888046309 0003046309  TRUE
5  003046309 0003046309  TRUE
6  465798132 0003046309 FALSE
7  465798132 0003046309 FALSE
8  465798132 0003046309 FALSE
9  465798132 0003046309 FALSE
10 465798132 0003046309 FALSE
11 465798132 0003046309 FALSE
12 465798132 0003046309 FALSE
13 465798132 0003046309 FALSE

【讨论】:

  • 它不能很好地推广到新数据:agrepl("8888", "8887", max.distance = 4) 返回TRUE(对于除0 之外的任何max.distance)。
  • 它应该为您的示例返回TRUE,因为它们部分匹配。但是如果你用grepl 试试,结果是FALSE。我知道这不是一个很好的解决方案,但仍然有一些 TRUEs 而不是所有 FALSE
  • 不,没关系,肯定有比这更好的解决方案,因为它只满足 OP 的最低要求。但我觉得还是比没有好。毕竟应该在更大的数据集上进行测试。
  • @slamballais agrepl 功能已被证明对我非常有用,但我不知道为什么用户不经常使用它。
  • 谢谢你!如果我想做四个或更多怎么办?我尝试了 max.distance >= 4)) 并产生了一个错误:“.amatch_bounds(max.distance) 中的错误:找不到对象'max.distance'”
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-10-08
  • 2023-01-14
  • 2019-08-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多