Использование индекса столбца и цикла для преобразования кадра данных - PullRequest
1 голос
/ 08 ноября 2019

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

Вот мои данные:

mydata<-structure(list(groupA = c("Rugby for Chipmunks", "Rugby for Chipmunks", "Rugby for Chipmunks", "Chafing Explained"), First = c(5, 3.57142857142857, 5, 4.5), groupB = c("Pylons for Priests", "Eating Creosote", "Eating Creosote", "Eating Creosote"), Second = c(4, 4, 3.16666666666667, 2.1666667), groupC = c("Wow for YOU!", "Advanced Cats for Bears", "Blue Paint Only", "Mockingbirds"), Third = c(5, 3, NaN, 4), groupD = c("How to Sell Pigeons", "How to Sell Pigeons", "How to Sell Pigoens", "Larger Boulders"), Fourth = c(4.3, 3, 4.1, 3.4), groupE = c("Making Money with Pears", "Making Money with Pears", "Why Walnuts?", "Responding to Idiots Part II"), Fifth = c(5, 3, 5, 4.16666666666667)), row.names = c(NA, -4L), class = c("tbl_df", "tbl", "data.frame"))

Я хочу использовать индексы, потому что мои будущие задачи будут иметь кадры данных с разными именами столбцов и шириной. Мой подход использует функцию, чтобы определить, является ли столбец нечетным / четным, а затем извлечь пары столбцов, пока я не достигну последнего нечетного пронумерованного столбца. Обратите внимание, что функция должна учитывать требуемый порядок нечетно-четных индексов для каждого извлечения (имя группы и соответствующий счет):

odd <- function(x) x%%2 != 0
outfile<-list()

moveit<-function(df){
  for (i in 1:dim(df)[2])    # define number of loops
    if (  i==dim(df)[2]-1  )  {break} # stop at least odd-numbered column
    if ( odd(i)==FALSE) {next}  # skip when i is not an odd numbered index 
  print(i)
  outfile[[i+1]]<-df[ ,c(i,i+1)]
}

result<-moveit(mydata)
str(result)

Вы можете видеть, что результатом является только последняя пара ключ-значение. Почему? Как настроить функцию для извлечения всех пар ключ-значение в один кадр данных?

Ответы [ 2 ]

3 голосов
/ 09 ноября 2019

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

nc <- ncol(mydata)
ig <- seq(1, nc, 2)  # indexes of key columns
reshape(as.data.frame(mydata), dir = "long", 
  varying = list(ig, -ig), v.names = c("key", "value"))

, давая:

    time                          key    value id
1.1    1          Rugby for Chipmunks 5.000000  1
2.1    1          Rugby for Chipmunks 3.571429  2
3.1    1          Rugby for Chipmunks 5.000000  3
4.1    1            Chafing Explained 4.500000  4
1.2    2           Pylons for Priests 4.000000  1
2.2    2              Eating Creosote 4.000000  2
3.2    2              Eating Creosote 3.166667  3
4.2    2              Eating Creosote 2.166667  4
1.3    3                 Wow for YOU! 5.000000  1
2.3    3      Advanced Cats for Bears 3.000000  2
3.3    3              Blue Paint Only      NaN  3
4.3    3                 Mockingbirds 4.000000  4
1.4    4          How to Sell Pigeons 4.300000  1
2.4    4          How to Sell Pigeons 3.000000  2
3.4    4          How to Sell Pigoens 4.100000  3
4.4    4              Larger Boulders 3.400000  4
1.5    5      Making Money with Pears 5.000000  1
2.5    5      Making Money with Pears 3.000000  2
3.5    5                 Why Walnuts? 5.000000  3
4.5    5 Responding to Idiots Part II 4.166667  4

2) pivot_longer Это можно сделать поочередно с помощью pivot_longer

library)(dplyr)
library(tidyr)

v.names <- c("key", "value")
mydata %>%
  setNames(outer(v.names, 1:(ncol(.)/2), paste)) %>%
  mutate(id = 1:n()) %>%
  pivot_longer(cols = -id, names_to = c(".value", "no"), names_sep = " ") %>%
  arrange(no, id)

Обратите внимание, что это похоже на использование pivot_longer здесь: Поворот по группам для неравного размера данных

Исправленный мовит

Вот ваш исправленный код.

moveit <- function(df) {
  outfile <- list()
  for(i in seq_along(df)) if (odd(i)) outfile[[(i+1)/2]] <- df[c(i, i+1)]
  outfile
}
1 голос
/ 09 ноября 2019

Мы можем создать числовой индекс с gl и split набором данных в list из data.frame, rename list элементов с map и объединить его в ряд

library(dplyr)
library(purrr)
split.default(mydata, as.integer(gl(ncol(mydata), 2, ncol(mydata)))) %>% 
      map_dfr(~ .x %>% 
                  rename_all(~ c('group', 'value')))

Вышесказанное также может быть преобразовано в No package zone

lst1 <-  split.default(mydata, as.integer(gl(ncol(mydata), 2, ncol(mydata)))) 
do.call(rbind, lapply(lst1, setNames, c("group", "value")))

В коде OP 'outfile' list инициализируется с длиной 0. Вместо этого он можетbe

odd <- function(x) x%%2 != 0
outfile <- vector('list', ncol(mydata))

moveit<-function(df){
  for (i in seq_along(df)) {   
    if(odd(i)){  
      outfile[[i]]<-df[ ,c(i,i+1)]
    }
 }
 Filter(Negate(is.null), outfile)
}

result <- moveit(mydata)

Кроме того, главная проблема заключается в том, что 'outfile' не возвращается в конце

odd <- function(x) x%%2 != 0
outfile<-list()
moveit<-function(df){
  for (i in 1:dim(df)[2]) {   # define number of loops
    if (  i==dim(df)[2]-1  )  {break} # stop at least odd-numbered column
    if ( odd(i)==FALSE) {next}  # skip when i is not an odd numbered index 
  print(i)
  outfile[[i+1]]<-df[ ,c(i,i+1)]
 }
 outfile
}

result<-moveit(mydata)

ПРИМЕЧАНИЕ. Здесь также не используются пакеты

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...