В списке фреймов данных добавьте одну переменную с ведущими нулями (в идеале со строчкой) - PullRequest
0 голосов
/ 15 февраля 2019

Я работаю со списком фреймов данных.В каждом фрейме данных я хотел бы заполнить одну переменную ID начальными нулями.Переменные ID являются символьными векторами и всегда являются первой переменной во фрейме данных.Однако в каждом фрейме данных переменная ID имеет разную длину.Например:

df1_id варьируется от 1:20, поэтому мне нужно заполнить до нуля, df2_id - от 1: 100, таким образом, мне нужно заполнить двумя нулями и т. Д.

У меня вопрос, как я могу дополнить каждый кадр данных без необходимости писать по одной строке кода для каждого кадра данных в списке.

Как уже упоминалось выше, я могу решить эту проблему с помощью str_padфункция на каждом кадре данных в отдельности.Например, см. Код ниже:

#Load stringr package
library(stringr)

#Create sample data frames
df1 <- data.frame("x" = as.character(1:20), "y" = rnorm(20, 10, 1), 
stringsAsFactors = FALSE)

df2 <- data.frame("v" = as.character(1:100), "y" = rnorm(100, 10, 1), 
stringsAsFactors = FALSE)

df3 <- data.frame("z" = as.character(1:1000), "y" = rnorm(1000, 10, 1), 
stringsAsFactors = FALSE)

#Combine data fames into list
dfl <- list(df1, df2, df3)

#Pad ID variables with leading zeros
dfl[[1]]$x <- str_pad(dfl[[1]]$x, width = 2, pad = "0")
dfl[[2]]$v <- str_pad(dfl[[2]]$v, width = 3, pad = "0")
dfl[[3]]$z <- str_pad(dfl[[3]]$z, width = 4, pad = "0")

Хотя это решение относительно неплохо работает для короткого списка, поскольку количество кадров данных увеличивается, оно становится немного громоздким.

Мне бы очень хотелось, если бы был способ, которым я мог бы встроить какой-то вектор "последовательности" в аргумент width функции str_pad.Примерно так:

dfl <- lapply(dfl, function(x) {x[,1] <- str_pad(x[,1], width = SEQ, pad = 
"0")})

где SEQ - вектор переменной длины.Используя приведенный выше пример, он будет выглядеть примерно так:

seq <- c(2,3,4)

Заранее спасибо, и, пожалуйста, дайте мне знать, если у вас есть какие-либо вопросы.

~ kj

1 Ответ

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

Здесь можно использовать Map, который предназначен для применения функции "к первым элементам каждого ... аргумента, вторым элементам, третьим элементам", подробности см. ?mapply.

library(stringr)
vec <- c(2,3,4) # this is the vector of 'widths', don't name it seq

Map(function(i, y) {
  dfl[[i]][, 1] <- str_pad(dfl[[i]][, 1], width = y, pad = "0")
  dfl[[i]] # this gets returned
}, 
# you iterate over these two vectors in parallel
i = 1:length(dfl), 
y = vec) 

Вывод

#[[1]]
#   x         y
#1 01  9.373546
#2 02 10.183643
#3 03  9.164371
#
#[[2]]
#    v         y
#1 001 11.595281
#2 002 10.329508
#3 003  9.179532
#4 004 10.487429
#
#[[3]]
#     z         y
#1 0001 10.738325
#2 0002 10.575781
#3 0003  9.694612
#4 0004 11.511781
#5 0005 10.389843

объяснение

Функция, которую мы передаем Map, является анонимной функцией, которую вы более или менее предоставили в своемвопрос:

function(i, y) {
  dfl[[i]][, 1] <- str_pad(dfl[[i]][, 1], width = y, pad = "0")
  dfl[[i]] # this gets returned
}

Вы видите, что функция принимает два аргумента, i и y (выберите другие имена, если вам нравится, например, df и width), и для каждого кадра данных в вашемсписок изменяет первый столбец dfl[[i]][, 1] <- ....Анонимная функция применяет str_pad к первому столбцу каждого фрейма данных

... <- str_pad(dfl[[i]][, 1], width = y, pad = "0")

, но вы видите, что мы не передаем фиксированное значение аргументу width, а y,

Возвращаясь к Map.Map теперь применяется str_pad к первому фрейму данных, с аргументом width = 2, применяется str_pad ко второму фрейму данных, с аргументом width = 3 и - вы, наверное, догадались - он применяет str_pad к третьему фрейму данныхв вашем списке с аргументом width = 4.

Аргументы указаны в последних двух строках кода как

i = 1:length(dfl), 
y = vec) 

Надеюсь, это поможет.


data

(рассмотрим создание примера minimal в следующий раз, так как количество строк в кадрах данных не имеет значения дляпроблема)

set.seed(1)
df1 <- data.frame("x" = as.character(1:3), "y" = rnorm(3, 10, 1), 
                  stringsAsFactors = FALSE)

df2 <- data.frame("v" = as.character(1:4), "y" = rnorm(4, 10, 1), 
                  stringsAsFactors = FALSE)

df3 <- data.frame("z" = as.character(1:5), "y" = rnorm(5, 10, 1), 
                  stringsAsFactors = FALSE)

#Combine data fames into list
dfl <- list(df1, df2, df3)
...