#r #data-cleaning #dplyr
#r #очистка данных #dplyr
Вопрос:
Я пытаюсь разделить столбец flags на несколько новых столбцов в r, используя mutate_at, а затем отдельные функции. Я упростил и очистил свое решение, как показано ниже, однако я получаю сообщение об ошибке, которое указывает на то, что в мою функцию передается весь столбец данных, а не каждая строка в отдельности. Является ли это нормальным поведением, которое просто требует, чтобы я перебирал каждый элемент x внутри моей функции? или я неправильно вызываю функцию mutate_at?
пример данных:
dataVariable <- data.frame(c_flags = c(".q.q.q","y..i.o","0x5a",".lll.."))
функции:
dataVariable <- read_csv("...",
col_types = cols(
c_date = col_datetime(format = ""),
c_dbl = col_double(),
c_flags = col_character(),
c_class = col_factor(c("a", "b", "c")),
c_skip = col_skip()
))
funTranslateXForNewColumn <- function(x){
binary = ""
if(startsWith(x, "0x")){
binary=hex2bin(x)
} else {
binary = c(0,0,0,0,0,0)
splitFlag = strsplit(x, "")[[1]]
for(i in splitFlag){
flagVal = 1
if(i=="."){
flagVal = 0
}
binary=append(binary, flagVal)
}
}
return(paste(binary[4:12], collapse='' ))
}
mutate_at(dataVariable, vars(c_flags), funs(funTranslateXForNewColumn(.)))
separate(dataVariable, c_flags, c(NA, "flag_1","flag_2","flag_3","flag_4","flag_5","flag_6","flag_7","flag_8","flag_9"), sep="")
Ошибка, которую я получаю, заключается в следующем:
Warning messages:
1: Problem with `mutate()` input `c_flags`.
i the condition has length > 1 and only the first element will be used
После перевода строки в соответствующее двоичное представление флагов я затем использую отдельную функцию, чтобы разделить ее на новые столбцы.
Комментарии:
1. и каков ваш ожидаемый результат для совместно используемых данных? Должен быть лучший способ сделать это, чем
for
цикл.2. флаги представляют собой конкатенацию строк значений true false, где . означает false, а любое другое значение означает true. этот же столбец также содержит некоторые шестнадцатеричные значения, которые я также перевожу в двоичный код. Полные функции проверяют, является ли его шестнадцатеричным значением, и соответствующим образом преобразуют оба в двоичную строку длиной 9. затем эта двоичная строка будет разделена на разные столбцы, причем каждый символ будет иметь свой собственный столбец
Ответ №1:
Аналогично логике OP, но, возможно, короче :
dataVariable$binFlags <- sapply(strsplit(dataVariable$c_flags, ''), function(x)
paste(as.integer(x != '.'), collapse = ''))
Если вы хотите сделать это, используя dplyr
, мы можем реализовать ту же логику, что и :
library(dplyr)
dataVariable %>%
mutate(binFlags = purrr::map_chr(strsplit(c_flags, ''),
~paste(as.integer(. != '.'), collapse = '')))
# c_flags binFlags
#1 .q.q.q 010101
#2 y..i.o 100101
#3 .lll.. 011100
mutate_at
/ across
используется, когда вы хотите применить функцию к нескольким столбцам. Более того, я не вижу здесь, что вы создаете только один новый двоичный столбец, а не несколько новых столбцов, как указано в вашем сообщении.
Комментарии:
1. Я упростил свой код для публикации. Реальные данные уже имеют некоторые значения в шестнадцатеричном формате, которые можно легко перевести в двоичный. Функция обрабатывает оба случая. Затем я использую: separate(dataVariable, c_flags, c(NA, «flag_1», «flag_2», «flag_3», «flag_4», «flag_5», «flag_6», «flag_7», «flag_8», «flag_9″), sep =»»)
2. не уверен, понимаю ли я. Похоже, это дает тот же результат, что и ваш код. Возможно, обновите пример, аналогичный вашим фактическим данным.
Ответ №2:
Я смог получить желаемый результат, заменив функцию mutate_at на:
dataVariable$binFlags <- mapply(funTranslateXForNewColumn, dataVariable$c_flags)
Однако я хочу знать, как правильно использовать функцию mutate_at .
заслуга: https://datascience.stackexchange.com/questions/41964/mutate-with-custom-function-in-r-does-not-work
Приведенная выше ссылка также включает в себя решение для запуска этой функции, которое заключается в векторизации функции:
v_funTranslateXForNewColumn <- Vectorize(funTranslateXForNewColumn)
mutate_at(dataVariable, vars(c_flags), funs(v_funTranslateXForNewColumn(.)))