如何创建一个自定义函数来使用purrr或lapply?

时间:2020-08-22 00:59:48

标签: r

我是一个初学者,想弄清楚如何不剪切和粘贴60行代码。 这是我的数据框

df <- data.frame(
  stringsAsFactors = FALSE,
                id = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L),
            people = c("marge","homer","homer",
                       "homer","marge","bart","homer","homer","marge")
)

我试图编写一个函数,以便我可以指定输入以使其更容易。 我实际上希望x是一个向量,但我什至无法将其用于单个观察。

lisaList <- function (x) {
    df[df$id==x, "people"] <- "lisa" 
}

#vector with the list of id's I want to change to "lisa"
myList=c(1,2,3)

我尝试过的不起作用

lisaList(myList)

这不起作用

lisaL <- function (x) {
   if(df$id==x) df[df$id==x, "people"] <- "lisa" }

lisaL(myList)

我也尝试使用mutate然后使用purrr编写一些东西,但我也无法弄清楚。

我希望将“ id”中等于1、2或3的每个观测值都更改为“ lisa”,所以我最终得到了这个

df <- data.frame(
  stringsAsFactors = FALSE,
                id = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L),
            people = c("lisa","lisa","lisa",
                       "homer","marge","bart","homer","homer","marge")
)

谢谢。

关注我的原始问题

谢谢你们!这些答案帮助我克服了障碍。 现在,通过向我的df添加另一列,我还有另外2个关于此功能的问题。 关注问题1 现在,我希望能够输入需要更改的观察值。

df <- data.frame(
  stringsAsFactors = FALSE,
                id = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9L),
            people = c("bart","lisa","lisa",
                       "homer","marge","bart","homer","homer","marge"),
                                   pets = c("dog","wolf","horse",
                       "bat","mouse","mole","gopher","bat","bat")
)

# new function
list3 <- function(dat, x, y) {
    dat %>%
        mutate(people = replace(people,  id %in% x, y))
}

myList=c(3,4,5)

list3 (df, myList, 'cat')

这行得通,但是我可以在函数中进行某些更改,因此用户无需使用''输入观察值?

我能够达到我想要的目标,但这需要创建一个新列表。

otherList <- c("ground hog")
list3 (df, myList, otherList)

关注问题2 现在,我希望用户能够输入要更改的列,而不是在函数中进行硬编码。我一直在试图弄清楚这一点(这就是为什么我认为我可以尝试在函数中使用mutate的替代方法),但是现在我感觉自己已经很亲密了,我想尝试一下如何做到这一点。

所以第一次尝试没有用。

list4 <- function(dat, x, y, z) {
    dat %>%
        mutate(z = replace(z,  id %in% x, y))
}

mycol <- c('pets')

list4(df, myList, 'birds', mycol)

这不起作用。

list4 <- function(dat, x, y, z) {
    dat %>%
        mutate((enquo(z)) = replace( (!!z),  id %in% x, y))
}

mycol <- c('pets')
list4(df, myList, 'birds', mycol)

许多其他版本尝试使用{{}}或指定enquo()和!!

您能帮我弄清楚如何输入列名吗?再次感谢你们俩的初步帮助!

2 个答案:

答案 0 :(得分:1)

我建议在ifelse管道中使用dplyr

lisaList <- function (x) {
  df%>%
    mutate(people=ifelse(id %in% x,"lisa", people))
}

myList=c(1,2,3)

lisaList(myList)

id people
1  1   lisa
2  2   lisa
3  3   lisa
4  4  homer
5  5  marge
6  6   bart
7  7  homer
8  8  homer
9  9  marge

关于第三个问题,您可以使用acrossmutate中指定变量名称。我已将函数的参数重命名为有助于提高可读性:

list3 <- function(dat, rowindex, replacestring, colnamevar) {

  dat %>%
    mutate(across(colnamevar, ~ifelse(id %in% rowindex, replacestring, .)))
}

list3(df, myList, 'birds', mycol)

id people   pets
1  1   bart    dog
2  2   lisa   wolf
3  3   lisa  birds
4  4  homer  birds
5  5  marge  birds
6  6   bart   mole

最后,不知道让R将未引用的文本识别为字符串而不是变量的方法。

答案 1 :(得分:0)

我们可以使用%in%代替==

df$people[df$id %in% 1:3] <- "lisa"

所以,函数应该是

lisaL <- function (dat, x) {
           dat$people[dat$id %in% x] <- "lisa" 
           dat
         }


lisaL(df, myList)
#  id people
#1  1   lisa
#2  2   lisa
#3  3   lisa
#4  4  homer
#5  5  marge
#6  6   bart
#7  7  homer
#8  8  homer
#9  9  marge

或将replacemutate一起使用

library(dplyr)
lisaList2 <- function(dat, x) {
       dat %>%
                mutate(people = replace(people,  id %in% x, 'lisa'))
   }

如果我们要使用==,那么一个选择是使用lapplyfor循环遍历'myList',创建逻辑向量Reduce使用|将其分配给单个逻辑向量并分配

listList3 <- function(dat, x) {
    dat$people[Reduce(`|`, lapply(x, function(u) dat$id == u))] <- 'lisa'
    dat
    }
listList3(df, myList)