2013-12-17 4 views
4

У меня есть кадр данных с двумя строковыми переменными с равным количеством символов. Эти строки представляют собой ответы учащихся на некоторые экзамены. Первая строка содержит знак + для ответа на каждый вопрос и неправильный ответ для каждого неправильного элемента. Вторая строка содержит все правильные ответы. Я хочу заменить все знаки + в первой строке правильным ответом из второй строки. Упрощенная эвристический набор данных может быть создан с помощью этого кода:Заменить заданный символ в строковой переменной с символом из другой строковой переменной равной длины

df <- data.frame(v1 = c("+AA+B", "D++CC", "A+BAD"), 
       v2 = c("DBBAD", "BDCAD","CDCCA"), stringsAsFactors = FALSE) 

Так + знаки в df$v1 должны быть заменены ж/букв в df$v2, которые на том же расстоянии от начала строки. Есть идеи?

ответ

10

Это работает в случае df$v1 и df$v2 персонажи:

regmatches(df$v1,gregexpr("\\+",df$v1))<-regmatches(df$v2,gregexpr("\\+",df$v1)) 

То есть:

df <- data.frame(v1 = c("+AA+B", "D++CC", "A+BAD"), 
       v2 = c("DBBAD", "BDCAD", "CDCCA"), stringsAsFactors = FALSE) 

rg <- gregexpr("\\+", df$v1) 
regmatches(df$v1, rg) <- regmatches(df$v2, rg) 
df 
#  v1 v2 
# 1 DAAAB DBBAD 
# 2 DDCCC BDCAD 
# 3 ADBAD CDCCA 
+0

Волшебное :) +1 конечно! –

+0

Удивительный. Это отлично работает. Я отредактирую свой код, чтобы предотвратить его создание. – Braden

2

Скорее всего, есть лучший подход, но вот о том, где я делаю две колонки, в матрицах, а затем ключ поиска:

## df<-data.frame(v1 = c("+AA+B", "D++CC", "A+BAD"), v2 = c("DBBAD", "BDCAD","CDCCA")) 
dats <- lapply(df, function(x) do.call(rbind, strsplit(as.character(x), ""))) 

dats[[1]][dats[[1]] == "+"] <- dats[[2]][dats[[1]] == "+"] 

apply(dats[[1]], 1, paste, collapse = "") 
## [1] "DAAAB" "DDCCC" "ADBAD" 

Я думал, что это один может быть интересным для сравнения:

Unit: microseconds 
    expr  min  lq median  uq  max neval 
Andrea() 296.693 313.953 321.884 328.4155 2443.051 1000 
    Josh() 300.891 314.420 319.551 326.5500 3748.779 1000 
    Tyler() 144.148 155.344 159.543 164.2080 2233.593 1000 
Jibler() 174.937 188.932 193.597 198.7290 2269.514 1000 
Alexis() 154.877 167.007 171.672 175.4040 2342.753 1000 
Julius() 394.658 413.317 420.315 429.4120 2549.412 1000 

enter image description here

+0

Почему три 'lapply's? вы можете получить 'dats', используя только один:' lapply (df, function (x) do.call (rbind, strsplit (as.character (x), ""))) '. –

+1

@Jiber, я возился и надел ответчик. Я починю его. –

3

Это одна кажется действительно, тоже:

mapply(function(x, y) paste0(ifelse(x == "+", y, x), collapse = ""), 
       strsplit(as.character(df$v1), ""), strsplit(as.character(df$v2), "")) 
#[1] "DAAAB" "DDCCC" "ADBAD" 
+1

отличное использование 'ifelse' –

1
df<-data.frame(v1 = c("+AA+B", "D++CC", "A+BAD"), 
       v2 = c("DBBAD", "BDCAD","CDCCA"), 
       stringsAsFactors = F) 


f <- function(x , y){ 
    xs <- unlist(strsplit(x, split = "")) 
    ys <- unlist(strsplit(y, split = "")) 
    paste(ifelse(xs == "+", ys , xs), collapse = "") 
} 

vapply(df$v1, f , df$v2, FUN.VALUE = character(1)) 
2

На основании ответа Тайлер RINKER, в концептуально это то же самое, но используя только один lapply и ifelse.

> dats <- lapply(df, function(x) do.call(rbind, strsplit(as.character(x), ""))) 
> apply(with(dats, ifelse(v1=="+", v2, v1)), 1, paste0, collapse="") 
[1] "DAAAB" "DDCCC" "ADBAD" 
Смежные вопросы