R 如果;“正确”;价值存在

R 如果;“正确”;价值存在,r,duplicates,R,Duplicates,我的数据由两个变量组成,一个id和一个相应的name。名称可以是两件事。id或一串字母 如果存在非数字名称,我需要用此值替换任何数字名称 数据示例 df <- data.frame(id = c("100", "100", "101", "102", "103", "104", "104", "105", "100", "106"), name = c("100", "A", "B", "C", "D", "104", "E", "F", "100", "106

我的数据由两个变量组成,一个
id
和一个相应的
name
名称可以是两件事。id或一串字母

如果存在非数字名称,我需要用此值替换任何数字名称

数据示例

df <- data.frame(id = c("100", "100", "101", "102", "103", "104", "104", "105", "100", "106"), 
             name = c("100", "A", "B", "C", "D", "104", "E", "F", "100", "106"), 
             correct_name = c("A", "A", "B", "C", "D", "E", "E", "F", "A", "106"), stringsAsFactors = F)
df快速肮脏方式:

sapply(1:nrow(df),function(x){
  if (is.na(as.numeric(df$id[x]))==FALSE){
    ind=which(df$id==df$id[x])
    ind2=which(is.na(as.numeric(as.character((df$name[ind]))))==TRUE)
    df$name[x]<<-df$name[ind[ind2[1]]]
  }
})
df
   id name correct_name
1 100    A            A
2 100    A            A
3 101    B            B
4 102    C            C
5 103    D            D
6 104    E            E
7 104    E            E
8 105    F            F
9 100    A            A
sapply(1:nrow(df),函数(x){
if(is.na(as.numeric(df$id[x]))==FALSE){
ind=哪个(df$id==df$id[x])
ind2=哪个(是.na(作为.numeric(作为.character((df$name[ind])))==TRUE)
df$name[x]编辑

由于您已经提到,在这种情况下,我们可以修改
ave
选项,检查条件并在一次调用中全部替换值,因此有一些
id
name
要替换

df$name <- with(df, ave(name, id, FUN = function(x) {
   inds = grepl("[0-9]+", x)
   if (any(!inds)) 
    replace(x, inds, x[which.max(!inds)])
   else
    x
}))

df
#    id name correct_name
#1  100    A            A
#2  100    A            A
#3  101    B            B
#4  102    C            C
#5  103    D            D
#6  104    E            E
#7  104    E            E
#8  105    F            F
#9  100    A            A
#10 106  106          106

并使用与基本R
ave相同的逻辑

#Replace the numbers with NA
df$name[grepl("[0-9]+", df$name)] <- NA

#Change the NA's to first non-NA value in the group
df$name <- with(df,ave(name, id, FUN = function(x) x[!is.na(x)][1]))

PS-我刚刚在data.frame调用中添加了
stringsAsFactors=FALSE
,以使列成为字符。

使用
dplyr
ifelse
grepl
的解决方案,模式设置为
“\\d+”
(即:数字)

编辑:可能只有一个
变异

df %>% 
  group_by(id) %>% 
  mutate(namenew = ifelse(
    grepl("\\d+", name),   # match for digits in the string
    name[!grepl("\\d+", name)][1], # if TRUE, substitute with the first non-digit
    name # if FALSE, keep it
  )) 
#    id name correct_name namenew
# 1 100  100            A       A
# 2 100    A            A       A
# 3 101    B            B       B
# 4 102    C            C       C
# 5 103    D            D       D
# 6 104  104            E       A
# 7 104    E            E       E
# 8 105    F            F       F
# 9 100  100            A       A

与我上面的解决方案相比,可能更清楚发生了什么。(类似于@Ronak Shah)

数据(
stringsAsFactors
很重要):


df或者,这可以通过使用查找表的更新联接来解决:

查找表是通过过滤非数字条目的
df
创建的:

library(data.table)
setDT(df)[!name %like% "^\\d+$"]
现在,
df
与查找表连接,在找到匹配项的地方,
name
被查找表中相应的条目替换。否则,
name
保持不变:

setDT(df)[df[!name %like% "^\\d+$"], on = "id", name := i.name]
df

什么是
[1]
do?@NelsonGon每个组中可以有多个非NA的
名称
,但我们只能用一个值替换它,因此我们将其子集,并从每个组中选择第一个非NA值。很好。我们如何确保不重复我们正在替换的内容?这就是假设。将有相同的
名称
实际上,每个
id
的值最终都采用了类似的解决方案,但并没有这样整洁。
library(dplyr)
df %>% 
  group_by(id) %>%
  mutate(namenew = ifelse(
    grepl("\\d+", name), 
    NA,
    name
  )) %>% 
  mutate(namenew = ifelse(
    is.na(namenew),
    namenew[!is.na(namenew)][1],
    namenew
  ))


#    id name correct_name namenew
# 1 100  100            A       A
# 2 100    A            A       A
# 3 101    B            B       B
# 4 102    C            C       C
# 5 103    D            D       D
# 6 104  104            E       A
# 7 104    E            E       E
# 8 105    F            F       F
# 9 100  100            A       A
df <- data.frame(id = c("100", "100", "101", "102", "103", "104", "104", "105", "100"), 
                 name = c("100", "A", "B", "C", "D", "104", "E", "F", "100"), 
                 correct_name = c("A", "A", "B", "C", "D", "E", "E", "F", "A"), stringsAsFactors = F)
library(data.table)
setDT(df)[!name %like% "^\\d+$"]
    id name correct_name
1: 100    A            A
2: 101    B            B
3: 102    C            C
4: 103    D            D
5: 104    E            E
6: 105    F            F
setDT(df)[df[!name %like% "^\\d+$"], on = "id", name := i.name]
df
     id name correct_name
 1: 100    A            A
 2: 100    A            A
 3: 101    B            B
 4: 102    C            C
 5: 103    D            D
 6: 104    E            E
 7: 104    E            E
 8: 105    F            F
 9: 100    A            A
10: 106  106          106