Используйте цикл для создания списков внутри другого списка - PullRequest
0 голосов
/ 24 февраля 2019

Я хотел бы создать два списка внутри другого списка.Обычно мне приходится создавать по 50 штатов для каждого штата США, и я ищу способ сделать это быстрее.

State <- c("ALABAMA", "ALABAMA", "ALASKA", "ALASKA")
Num <- c(5, 6, 7, 8)
d <- data.frame(State, Num)

uni<-unique(d$State)

data = list(
  for(i in 1 : length(uni)){
    list[[i]](
      name = un[i],
      y = summarise(sum(d$Num[D$State==uni[i]])),
      drilldown = tolower(un[i])
    )
  }
)

Более конкретно, я хочу, чтобы каждый список включал name изState заглавными буквами, y в виде суммы Num и drilldown в качестве названия State заглавными буквами.Результат должен выглядеть примерно так:

name="ALABAMA"
y= 11
drilldown="alabama"

name="ALASKA"
y= 15
drilldown="alaska"

Вручную это будет выглядеть так:

data = list(

      list(
        name = "ALABAMA",
        y = 11,
        drilldown = "alabama"
      ),
      list(
        name = "ALASKA",
        y = 15,
        drilldown = "alaska"
      )

    )

, который дает список из 2 списков из 3 объектов.

Можетвозможно без for(), поэтому я открыт для других предложений

Ответы [ 4 ]

0 голосов
/ 24 февраля 2019

Вы можете быстро набрать rowsum(), чтобы получить групповые суммы, затем Map(), чтобы собрать список из его частей.

xx <- with(d, rowsum(Num, State))
Map(list, name=rownames(xx), y=xx, drilldown=tolower(rownames(xx)), USE.NAMES=FALSE)
# [[1]]
# [[1]]$name
# [1] "ALABAMA"
#
# [[1]]$y
# [1] 11
#
# [[1]]$drilldown
# [1] "alabama"
#
#
# [[2]]
# [[2]]$name
# [1] "ALASKA"
#
# [[2]]$y
# [1] 15
#
# [[2]]$drilldown
# [1] "alaska"
0 голосов
/ 24 февраля 2019

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

Этот тип задачи идеально подходит для пакета dplyr, использующего каналы:

library(dplyr)

df_result <- d %>%
  group_by(State) %>%
  summarise(y = sum(Num),
            drilldown = tolower(first(State)))

print(df_result)

дает:

# A tibble: 2 x 3
  State       y drilldown
  <fct>   <dbl> <chr>    
1 ALABAMA    11 alabama  
2 ALASKA     15 alaska

Если вы хотите получить вложенный список, как в примере вывода вместо data.frame, вы можете дополнительно использовать transpose() из purrr Пакет:

library(purrr)

transpose(df_result)

дает:

[[1]]
[[1]]$State
[1] "ALABAMA"

[[1]]$y
[1] 11

[[1]]$drilldown
[1] "alabama"


[[2]]
[[2]]$State
[1] "ALASKA"

[[2]]$y
[1] 15

[[2]]$drilldown
[1] "alaska"
0 голосов
/ 24 февраля 2019
State <- c("ALABAMA", "ALABAMA", "ALASKA", "ALASKA")
Num <- c(5, 6, 7, 8)
d <- data.frame(State, Num, stringsAsFactors = F)

Решение 1: Use built-in packages

df1 <- within(aggregate(Num ~ State, d, FUN = sum), drilldown <- tolower(State))
output1 <- lapply(split(df1, 1:nrow(df1)), c)
str(output1)

# List of 2
#  $ 1:List of 3
#   ..$ State    : chr "ALABAMA"
#   ..$ Num      : num 11
#   ..$ drilldown: chr "alabama"
#  $ 2:List of 3
#   ..$ State    : chr "ALASKA"
#   ..$ Num      : num 15
#   ..$ drilldown: chr "alaska"

Решение 2: library(tidyverse)

output2 <- d %>% group_by(State) %>%
                 summarise(Num = sum(Num)) %>%
                 mutate(drilldown = tolower(State)) %>% 
                 transpose  # purrr::transpose
str(output2)

# List of 2
#  $ :List of 3
#   ..$ State    : chr "ALABAMA"
#   ..$ Num      : num 11
#   ..$ drilldown: chr "alabama"
#  $ :List of 3
#   ..$ State    : chr "ALASKA"
#   ..$ Num      : num 15
#   ..$ drilldown: chr "alaska"
0 голосов
/ 24 февраля 2019

Хотите что-то вроде следующего?Он использует split для создания списка фреймов данных, по одному на State, а затем lapply анонимной функции для каждого из df.

Здесь представлены две версии с различными форматами вывода: объект класса "list" и объект класса "data.frame".

lapply(split(d, d$State), function(DF){
  s <- as.character(DF[["State"]][1])
  list(
    State = s,
    y = sum(DF[["Num"]]),
    drilldown = tolower(s)
  )
})

lapply(split(d, d$State), function(DF){
  s <- as.character(DF[["State"]][1])
  data.frame(
    State = s,
    y = sum(DF[["Num"]]),
    drilldown = tolower(s)
  )
})

EDIT.

Первый способ выводит список из двух именованных списков.Если вы хотите, чтобы эти списки были безымянными, сделайте то, что G.Комментарий Гротендика предлагает.

data <-lapply(unname(split(d, d$State)), function(DF){
  s <- as.character(DF[["State"]][1])
  list(
    State = s,
    y = sum(DF[["Num"]]),
    drilldown = tolower(s)
  )
})
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...