Как избежать цикла в R: выбор элементов из списка

list r vector strsplit

32254 просмотра

10 ответа

Я мог бы решить это с помощью циклов, но я пытаюсь думать в векторах, чтобы мой код был более R-esque.

У меня есть список имен. Формат имя_фамилия. Я хочу вывести из этого списка отдельный список только с именами. Я не могу понять, как это сделать. Вот некоторые примеры данных:

t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
tsplit <- strsplit(t,"_")

который выглядит так:

> tsplit
[[1]]
[1] "bob"   "smith"

[[2]]
[1] "mary" "jane"

[[3]]
[1] "jose"  "chung"

[[4]]
[1] "michael" "marx"   

[[5]]
[1] "charlie" "ivan"   

Я мог бы получить то, что я хочу, используя такие циклы:

for (i in 1:length(tsplit)){
    if (i==1) {t_out <- tsplit[[i]][1]} else{t_out <- append(t_out, tsplit[[i]][1])} 
}

который дал бы мне это:

t_out
[1] "bob"     "mary"    "jose"    "michael" "charlie"

Так как я могу сделать это без петель?

Автор: JD Long Источник Размещён: 04.10.2019 11:12

Ответы (10)


26 плюса

Решение

Вы можете использовать apply(или sapply)

t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
f <- function(s) strsplit(s, "_")[[1]][1]
sapply(t, f)

bob_smith    mary_jane   jose_chung michael_marx charlie_ivan 

       "bob"       "mary"       "jose"    "michael"    "charlie" 

Смотрите: краткое введение, чтобы «применить» в R

Автор: liebke Размещён: 31.08.2009 01:16

43 плюса

И еще один подход:

t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
pieces <- strsplit(t,"_")
sapply(pieces, "[", 1)

Словом, последняя строка извлекает первый элемент каждого компонента списка, а затем упрощает его в вектор.

Как это работает? Ну, вы должны понимать альтернативный способ написания x[1]является "["(x, 1), то есть функция называется , [что делает Подменит. sapplyВызов применяется вызывает эту функцию один раз для каждого элемента исходного списка, передавая два аргумента, элемент списка и 1.

Преимущество этого подхода перед другими заключается в том, что вы можете извлечь несколько элементов из списка без необходимости повторного вычисления разбиений. Например, фамилия будет sapply(pieces, "[", 2). Как только вы привыкнете к этому идиому, его довольно легко прочитать.

Автор: hadley Размещён: 31.08.2009 03:20

10 плюса

Как насчет:

tlist <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
fnames <- gsub("(_.*)$", "", tlist)
# _.* matches the underscore followed by a string of characters
# the $ anchors the search at the end of the input string
# so, underscore followed by a string of characters followed by the end of the input string

для подхода RegEx?

Автор: William Doane Размещён: 31.08.2009 02:33

9 плюса

что о:

t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")

sub("_.*", "", t)
Автор: Karsten Размещён: 22.01.2010 06:29

7 плюса

Я сомневаюсь, что это самое элегантное решение, но оно превосходит циклы:

t.df <- data.frame(tsplit)
t.df[1, ]

Преобразование списков во фреймы данных - это единственный способ заставить их делать то, что я хочу. Я с нетерпением жду, чтобы прочитать ответы людей, которые действительно понимают, как обрабатывать списки.

Автор: Matt Parker Размещён: 31.08.2009 01:12

4 плюса

У тебя почти было это. Это действительно только вопрос

  1. используя одну из *applyфункций, чтобы перебрать существующий список, я часто начинаю с, lapplyа иногда переключаюсь наsapply
  2. добавить анонимную функцию, которая одновременно работает с одним из элементов списка
  3. Вы уже знали, что это было, strsplit(string, splitterm)и что вам нужно нечетное, [[1]][1]чтобы выбрать первый термин ответа
  4. просто сложите все вместе, начиная с предпочтительной переменной namne (поскольку мы остаемся в стороне от tor cи друзей)

который дает

> tlist <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan") 
> fnames <- sapply(tlist, function(x) strsplit(x, "_")[[1]][1]) 
> fnames 
  bob_smith    mary_jane   jose_chung michael_marx charlie_ivan   
      "bob"       "mary"       "jose"    "michael"    "charlie" 
>
Автор: Dirk Eddelbuettel Размещён: 31.08.2009 01:09

3 плюса

Вы можете использовать unlist():

> tsplit <- unlist(strsplit(t,"_"))
> tsplit
 [1] "bob"     "smith"   "mary"    "jane"    "jose"    "chung"   "michael"
 [8] "marx"    "charlie" "ivan"   
> t_out <- tsplit[seq(1, length(tsplit), by = 2)]
> t_out
[1] "bob"     "mary"    "jose"    "michael" "charlie"

Возможно, есть лучший способ извлечь только записи с нечетным индексом, но в любом случае у вас не будет цикла.

Автор: brentonk Размещён: 31.08.2009 01:10

2 плюса

И еще один подход, основанный на примере unlist Брентонка ...

tlist <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
tsplit <- unlist(strsplit(tlist,"_"))
fnames <- tsplit[seq(1:length(tsplit))%%2 == 1]

Автор: William Doane Размещён: 31.08.2009 02:56

1 плюс

Я бы использовал следующий метод на основе unlist ():

> t <- c("bob_smith","mary_jane","jose_chung","michael_marx","charlie_ivan")
> tsplit <- strsplit(t,"_")
> 
> x <- matrix(unlist(tsplit), 2)
> x[1,]
[1] "bob"     "mary"    "jose"    "michael" "charlie"

Большим преимуществом этого метода является то, что он решает эквивалентную проблему для фамилий одновременно:

> x[2,]
[1] "smith" "jane"  "chung" "marx"  "ivan" 

Недостатком является то, что вы должны быть уверены, что все имена соответствуют firstname_lastnameструктуре; если нет, то этот метод сломается.

Автор: jmc200 Размещён: 07.09.2012 06:42

0 плюса

из исходного tsplitобъекта списка, указанного в начале, эта команда будет делать:

unlist(lapply(tsplit,function(x) x[1]))

он извлекает первый элемент из всех элементов списка, а затем преобразует список в вектор. Разблокировать сначала матрицу, а затем извлечь первый столбец - тоже нормально, но тогда вы зависите от того факта, что все элементы списка имеют одинаковую длину. Вот вывод:

> tsplit

[[1]]
[1] "bob"   "smith"

[[2]]
[1] "mary" "jane"

[[3]]
[1] "jose"  "chung"

[[4]]
[1] "michael" "marx"   

[[5]]
[1] "charlie" "ivan"   

> lapply(tsplit,function(x) x[1])

[[1]]
[1] "bob"

[[2]]
[1] "mary"

[[3]]
[1] "jose"

[[4]]
[1] "michael"

[[5]]
[1] "charlie"

> unlist(lapply(tsplit,function(x) x[1]))

[1] "bob"     "mary"    "jose"    "michael" "charlie"
Автор: Virginie Размещён: 28.02.2013 10:53
Вопросы из категории :
32x32