R - change column content with function to new content

Viewed 55

Alright my problem is, that I have a dataframe with a column with species names like this:

  1. Genus1 species1
  2. Genus1 species2
  3. Genus2 species3

And I simply want to cut the genus names like this:

  1. G. species1
  2. G. species2
  3. G. species3

My problem isn't the string manupilation. I'll just can't figure it out how to simply use my function that looks like this:

truncateGenusName <- function(x){
  genus <- str_sub(x, 1, 1) 
  posOfSpace <- str_locate(x, " ")[1] 
  epitheton <- str_sub(x, posOfSpace, str_length(x)) 
  paste0(genus, '. ', epitheton)
}

I was trying to call the function like this:
mutate(data, species = replace (species, TRUE, truncateGenusName(species)))

The problem with this call is that not a single string is passed to the function, but a list.

I guess my approach is way too complicated. Does maybe someone have a shortcut?

2 Answers

Here is a solution using dplyr, tidyr, and stringr.

separate from the tidyr package is used to turn the names column into two new columns genus and species.

str_trunc from the stringr package truncates the strings in the genus column. Note that the default is to apply three ellipses indicating that the string has been truncated. Using ellipsis = "." overrides that default to show only 1 ellipse.

paste has a default sep = " ", so it is preferable over paste0 in my opinion.

library(tibble) # Used to create a reproducible example. 
library(dplyr)
library(tidyr)
library(stringr)

# create a reproducible example dataset using the tibble package. 

df <- tibble(
  names = c("Genus1 species1",
            "Genus1 species2",
            "Genus1 species3")
)


# code to format the names column. 

df %>% 
  separate(names, c("genus", "species"), sep = " ") %>% 
  mutate(genus = str_trunc(genus, 2, ellipsis = ".")) %>% 
  mutate(
    genus_species = paste(genus, species)
  ) %>% 
  rename(names = genus_species) %>%
  select(names)

# output table

#> # A tibble: 3 x 1
#>   names      
#>   <chr>      
#> 1 G. species1
#> 2 G. species2
#> 3 G. species3

Created on 2020-11-19 by the reprex package (v0.3.0)

Original table:

#> # A tibble: 3 x 1
#>   names          
#>   <chr>          
#> 1 Genus1 species1
#> 2 Genus1 species2
#> 3 Genus1 species3

Simple one-liner in base R:

dat <- read.table(text = "
    Genus1 species1
    Genus1 species2
    Genus2 species3
")

dat$V3 <- paste0(gsub("(?<=^.{1}).*", "", dat$V1, perl = TRUE), ". ", dat$V2)

dat

#       V1       V2          V3
# 1 Genus1 species1 G. species1
# 2 Genus1 species2 G. species2
# 3 Genus2 species3 G. species3

Since I had misinterpreted the OP, a new one-liner solution (still just base R):

dat <- read.table(text = "
    Genus1 species1
    Genus1 species2
    Genus2 species3
")

dat$V3 <- paste0(dat$V1, " ", dat$V2)
dat <- dat[, 3, drop = FALSE]
dat

#                V3
# 1 Genus1 species1
# 2 Genus1 species2
# 3 Genus2 species3

#One-liner below:
dat$V3 <- gsub("(?<=^.{1})[A-Za-z0-9]+(?= )", ".", dat$V3, perl = TRUE)

dat
#            V3
# 1 G. species1
# 2 G. species2
# 3 G. species3
Related