如何在多列上使用map()函数

时间:2018-08-24 16:38:13

标签: r

我有一个看起来像这样的数据框:

x1   x2   x3     x4   ...
56   45   34    76    ...
56+3 56   42    43    ...
38   53   56-1  55+3  ...
...   ...   ...  ...   ...

在超过30列的每一行中,我只希望保留前2个字符,因此基本上我想删除所有这些“ +3”,“-1”等。因此最后我将拥有:

x1   x2   x3     x4   ...
56   45   34    76    ...
56   56   42    43    ...
38   53   56    55    ...
...   ...   ...  ...   ...

我使用下面的代码在单个列中进行了更改,但是我希望能够一次在多个列上实现它。最后,您可以看到我需要使每列成为一个因素。

A <- substr(data$x1, start = 1, stop = 2)
data$x1 <- as.factor(A) 

我考虑过使用purrr中的map函数,但是我不知道该怎么做。

5 个答案:

答案 0 :(得分:1)

我们可以使用sub来删除这些字符,方法是匹配+-,后跟数字(\\d+)到末尾($)字符串,将其转换为numeric并将输出分配回原始数据集

df[] <- lapply(df, function(x) as.numeric(sub("[+-]\\d+$", "", x)))
df
#  x1 x2 x3 x4
#1 56 45 34 76
#2 56 56 42 43
#3 38 53 56 55

使用tidyverse

library(tidyverse)
df %>%
    mutate_all(funs(as.numeric(str_remove(., "[+-]\\d+$"))))

数据

df <- structure(list(x1 = c("56", "56+3", "38"), x2 = c(45L, 56L, 53L
), x3 = c("34", "42", "56-1"), x4 = c("76", "43", "55+3")), 
class = "data.frame", row.names = c(NA, -3L))

答案 1 :(得分:1)

使用正则表达式解决方案和winmm.lib,我们可以从每个单元格返回一组任何东西,后跟apply+,后跟任意数量的数字。

-

使用apply(df,c(1,2),function(x) gsub('(.*)[+-]\\d+','\\1',x)) x1 x2 x3 x4 [1,] "56" "45" "34" "76" [2,] "56" "56" "42" "43" [3,] "38" "53" "56" "55"

map

数据

library(dplyr)
library(purrr)
#map_df(df,~gsub('(.*)[+-]\\d+','\\1',.x))
df %>% map_df(.,~gsub('(.*)[+-]\\d+','\\1',.x)) %>%
       mutate_at(vars(starts_with("x")),as.factor)  #Change any var start with x to factor

# A tibble: 3 x 4
  x1    x2    x3    x4   
 <fct> <fct> <fct> <fct>
1 56    45    34    76   
2 56    56    42    43   
3 38    53    56    55 

答案 2 :(得分:1)

类似于@akrun的答案,但带有str_extract

library(dplyr)
df %>%
  mutate_all(~ as.numeric(str_extract(., "^\\d+")))

,或者如果输出不需要为数字,则只需以下内容:

df %>%
  mutate_all(str_extract, "^\\d+")

结果:

  x1 x2 x3 x4
1 56 45 34 76
2 56 56 42 43
3 38 53 56 55

数据:

df <- structure(list(x1 = structure(c(2L, 3L, 1L), .Label = c("38", 
"56", "56+3"), class = "factor"), x2 = c(45L, 56L, 53L), x3 = structure(1:3, .Label = c("34", 
"42", "56-1"), class = "factor"), x4 = structure(c(3L, 1L, 2L
), .Label = c("43", "55+3", "76"), class = "factor")), .Names = c("x1", 
"x2", "x3", "x4"), class = "data.frame", row.names = c(NA, -3L
))

答案 3 :(得分:1)

您可以使用sub仅捕获前两个字符,即(^.{2}).*甚至是(^..).*,然后将所有内容替换为捕获的组,即\\1。现在,这将创建一个字符矩阵:

sub("(^.{2}).*","\\1",as.matrix(df))
     x1   x2   x3   x4  
[1,] "56" "45" "34" "76"
[2,] "56" "56" "42" "43"
[3,] "38" "53" "56" "55"

您现在需要的是在保持尺寸的同时将所有这些都设为数字,因此我们调用array(...,dim(df))structure(...,.Dim = dim(df)),然后转换为data.frame()

data.frame(array(as.numeric(sub("(^.{2}).*","\\1",as.matrix(df))),dim(df)))
  X1 X2 X3 X4
1 56 45 34 76
2 56 56 42 43
3 38 53 56 55

答案 4 :(得分:0)

readr::parse_num将提取找到的拳头编号,忽略其余部分,然后转换为数字。我们将其与dplyr::mutate_all一起使用,因此我们将附加tidyverse,它将同时附加readrdplyr

library(tidyverse)
df %>% mutate_all(parse_number)
#   x1 x2 x3 x4
# 1 56 45 34 76
# 2 56 56 42 43
# 3 38 53 56 55