Застібнути або перерахувати в R?


84

Які еквіваленти R для цих розумінь списку Python:

[(i,j) for i,j in zip(index, Values)]
[(i,j) for i,j in enumerate(Values)]
[(i,j) for i,j in enumerate(range(10,20))]   %MWE, indexing or enumerating to 
                                            %keep up with the index, there may 
                                            %be some parameter to look this up

Приклад з результатом

>>> [(i,j) for i,j in enumerate(range(10,20))]
[(0, 10), (1, 11), (2, 12), (3, 13), (4, 14), (5, 15), (6, 16), (7, 17), (8, 18), (9, 19)]

Я вирішив цю проблему раніше за допомогою деякої хитрості в R, але вже не пам'ятаю, перша ідея - itertools -pkg, але я сподіваюся знайти більш ідіоматичний спосіб зробити це.


2
якби ви могли навести невеликий приклад для тих, хто не знайомий з Python, це може збільшити кількість потенційних відповідачів. Я здогадуюсь, що останнійexpand.grid(i=10:20,j=10:20)
Бен Болкер

@BenBolker: додав результат - тепер зрозуміло? Це може бути більш складним завданням, але логіка важлива ...
hhh

1
Я згоден з @DWin. Нерозумно очікувати співвідношення один до одного між структурами даних у R та Python. Якщо ви хочете отримати хороші відповіді, вам слід вказати, як ви хочете, щоб результат виглядав на R, а не на Python.
Джоран

До речі, ось акуратний спосіб as.vector(rbind(1:10, 11:20))
зафіксувати

Відповіді:


47

Відповідь на python enumerate:

У R впорядкований список (див. Цю відповідь ). Таким чином, все, що вам потрібно, це проіндексувати або ключі (за допомогою names()[i]), або значення (за допомогою [[i]]).

Використання seq_along(в якості альтернативи може зробити for(i in 1:length(mylist)){...}):

> mylist <- list('a'=10,'b'=20,'c'=30)
> for (i in seq_along(mylist)){
+   print(paste(i,names(mylist)[i],mylist[[i]]))
+ }
[1] "1 a 10"
[1] "2 b 20"
[1] "3 c 30"

Відповідь на python zip:

Дивіться одну з наведених вище відповідей, щоб імітувати список кортежів. Я віддаю перевагу фрейму даних, як показано у відповіді BondedDust:

> x <- 1:3
> y <- 4:6
> data.frame(x=x, y=y)
  x y
1 1 4
2 2 5
3 3 6

1
Щоб продовжити свій перший приклад до другого,data.frame(names=labels(mylist),values=unlist(mylist),row.names = 1:length(mylist))
Йодер

питання про ефективність: чи потрібно щоразу виконувати виклик імен (mylist) [i], чи це тривіальна операція? Мені цікаво, чи було б найкраще присвоїти це name_list перед циклом
markgalassi

42

Були деякі обговорення щодо розуміння списку для R, наприклад тут чи там . Хеш - пакет навіть пропонує словник структури. Однак, як казали інші, важко спробувати зіставити одні мовні засоби з іншими (навіть якщо це те, що насправді пропонує Порівняння мов програмування ) без чіткого розуміння того, до чого він повинен звикнути. Наприклад, я можу імітувати Python zip()на R наступним чином:

Python

In [1]: x = [1,2,3]
In [2]: y = [4,5,6]
In [3]: zip(x, y)
Out[3]: [(1, 4), (2, 5), (3, 6)]

Р.

> x <- 1:3
> y <- 4:6
> list(x, y)                     # gives a simple list
> as.list(paste(x, y))           # three tuples, as a list of characters
> mapply(list, x, y, SIMPLIFY=F) # gives a list of 3 tuples
> rbind(x, y)                    # gives a 2x3 matrix 

Як бачимо, це насправді залежить від того, що ви хочете зробити з результатом згодом.


1
Я думаю, що питання полягає в тому, що ви використовуєте, коли використовуєте zip в python. типове використання для розуміння списку з кількома аргументами, тому mapply обробляє це безпосередньо.
seanv507

6
Це mapplyте, що ми хочемо для прямого аналога.
StephenBoesch

@javadba mapplyохоплює найпоширеніший варіант використання: zip, потім map.
Йодер

8

Ще одним варіантом, який створить список векторів, є використання функції Map, як показано тут @peterhurford: https://rdrr.io/github/peterhurford/funtools/src/R/zippers.R

> x <- 1:3
> y <- 4:6
> z <- 7:9
> Map(c, x, y, z)
[[1]]
[1] 1 4 7

[[2]]
[1] 2 5 8

[[3]]
[1] 3 6 9

В Python, первинне використання поштового індексу є ітерація по кілька векторів / списків: for xi, yi in zip(x, y): .... +1 за найелегантніше рішення, яке я бачив до цього часу, щоб зробити це в R:for (xi.yi in Map(c, x, y)) { xi <- xi.yi[1]; yi <- xi.yi[2]; ... }
sgrubsmyon

6

Якщо це подання матриці на Python, тоді цей код:

j <- 10:20
matrix(c(seq_along(j), j), ncol=2)
#------------
      [,1] [,2]
 [1,]    1   10
 [2,]    2   11
 [3,]    3   12
 [4,]    4   13
 [5,]    5   14
 [6,]    6   15
 [7,]    7   16
 [8,]    8   17
 [9,]    9   18
[10,]   10   19
[11,]   11   20

Ви все ще залишаєте тих з нас, хто не є користувачами Python, у темряві щодо структури бажаного результату. Ви використовуєте термін "список", але результати пропонують упорядкований набір кортежів.

Враховуючи вказівки @ chi, ми також можемо запропонувати використовувати дуже R-орієнтовану структуру 'кадру даних'

x <- 1:3
y <- 4:6
dfrm <- data.frame(x=x, y=y)

... який має гнучкість списку з точки зору типів стовпців та особливостей доступу матриці з точки зору індексації рядків і стовпців. Або можна використати запит hhh і створити неявно індексовані значення j-вектора, 10:20використовуючи rownamesвектор, який починається з "1" за замовчуванням, але який можна змінити, щоб стати символьним вектором, починаючи з "0"

dfrm <- data.frame(j=10:20)
dfrm[3, ]
#[1] 12

 rownames(dfrm) <- 0:10
 dfrm["0",]
# [1] 10

На жаль, обережні виявлять, що dfrm [0,] не є щасливим дзвінком, повертаючи вектор довжиною 0.


+1 за елегантне рішення. (Ні, це не матриці Python, але, як ви вже здогадалися, перелік кортежів .)
chl

4

Для того, щоб використовувати розуміння списку стилів Python з переліченнями, такими як перераховані списки, одним із способів є встановлення пакету розуміння списку LC(розроблений 2018) та пакет itertools (розроблений 2015).

Перелік розумінь у R

Ви можете знайти LCпакет тут .

install.packages("devtools")
devtools::install_github("mailund/lc")

Приклад

> library(itertools); library(lc)
> lc(paste(x$index, x$value), x=as.list(enumerate(rnorm(5))), )
[[1]]
[1] "1 -0.715651978438808"

[[2]]
[1] "2 -1.35430822605807"

[[3]]
[1] "3 -0.162872340884235"

[[4]]
[1] "4 1.42909760816254"

[[5]]
[1] "5 -0.880755983937781"

де синтаксис програмування ще не такий чистий і відшліфований, як у Python, але функціонально працює та описується його довідка:

"Синтаксис виглядає так: lc (expr, списки, предикати), де expr - це якийсь вираз, що обчислюється для всіх елементів у списках, де списки - це один або кілька іменованих списків, де вони вказуються за допомогою імені та імені виразу = list_expr, і де предикати - це вирази, які слід обчислити до логічного значення. Наприклад, щоб отримати список усіх парних чисел у квадраті, зі списку x ми можемо записати lc (x ** 2, x = x, x% % 2 == 0). Результатом виклику lc є список, побудований із виразів у expr, для всіх елементів у вхідних списках, де предикати мають значення true. "

де зауважте, що предикати можна залишити порожніми, наприклад, у наведеному вище прикладі.

Інструменти та переліки у стилі Python

Ви можете використовувати itertools R, дуже схожі на itertools Python, далі в Cran тут

library(itertools)

де описано

"Різні інструменти для створення ітераторів, багато з яких мають шаблони після функцій у модулі itertools Python, а інші - за функціями у пакеті" сніг "."

Приклад. перерахування

> for (a in as.list(enumerate(rnorm(5)))) { print(paste(a$index, "index:", a$value))}
[1] "1 index: 1.63314811372568"
[1] "2 index: -0.983865948988314"
[1] "3 index: -1.27096072277818"
[1] "4 index: 0.313193212706331"
[1] "5 index: 1.25226639725357"

Приклад. перерахування за допомогою ZIP

> for (h in as.list(izip(a=1:5, b=letters[1:5]))) { print(paste(h$a, "index:", h$b))}
[1] "1 index: a"
[1] "2 index: b"
[1] "3 index: c"
[1] "4 index: d"
[1] "5 index: e"

4

zipі enumerateне є особливо складними для реалізації в R:

#' zip(1:5,1:10)
zip <- function(...) {
  mapply(list, ..., SIMPLIFY = FALSE)
}

Перелічити просто визначити з точки зору zip:

#' enumerate(l=LETTERS)
enumerate <- function(...) {
  zip(ix=seq_along(..1), ...)
}

Оскільки це належні функції, ми можемо використовувати їх, ...щоб зробити їх досить гнучкими та стислими, і скористатися поведінкою mapply, наприклад, переробкою вхідних даних та правильним іменуванням виводу.


1
Вони були додані до stackoverflowпакету, fwiw.
Ніл Фульц,

0
# similar to python. return a list of list. Short sequences get recycled.
zip <- function(...){ 
    all.list <- list(...)
    ele.names <- names(all.list)
    max.length <- max(sapply(all.list, length))
    lapply(0:(max.length - 1), function(i) {
        res <- lapply(all.list, function(l) l[i %% length(l) + 1]) 
        names(res) <- ele.names
        res
    })
}

Будь ласка, надайте опис того, що робить цей блок коду.
Кейван Есбаті,

ця функція робить те саме те саме з "mapply (list, x, y, SIMPLIFY = F)", на який вказав
@chl

0

Цього можна досягти за допомогою двох операторів вставки:

str1 <- paste(1:11, 10:20, sep=",", collapse='), (')
paste("(", str1, ")", sep = "")

Результат сподобається наступним:

'(1,10), (2,11), (3,12), (4,13), (5,14), (6,15), (7,16), (8,17), (9,18), (10,19), (11,20)'

0

Для python 'перелічити' еквівалент у R. Зберігання векторів у списку та ітерація над ними за допомогою індексу повинна працювати нормально.

vect1 <- c('A', 'B', 'C')
vect2 <- c('a', 'b', 'c')

# eqiv to zip values:
idx_list <- list(vect1, vect2)
idx_vect <- c(1:length(idx_list[[1]]))

for(i in idx_vect){
    x <- idx_list[[1]][i]
    j <- idx_list[[2]][i]
    print(c(i, x, j))
}

Вихід:

[1] "1" "A" "a"
[1] "2" "B" "b"
[1] "3" "C" "c"

R 'list' - приємний банк для депонування векторів та збереження за допомогою індексу.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.