在数据帧列表中,用前导零填充一个变量(最好使用 stringr)

In a list of data frames, pad one variable with leading zeros (ideally w/ stringr)

我正在处理数据框列表。在每个数据框中,我想用前导零填充单个 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")

虽然此解决方案对于短列表的效果相对较好,但随着数据帧数量的增加,它会变得有点笨拙。

如果有一种方法可以将某种 "sequence" 向量嵌入到 str_pad 函数的宽度参数中,我会很高兴。像这样:

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

其中 SEQ 是可变长度的向量。使用上面的示例,它看起来像:

seq <- c(2,3,4)

在此先感谢,如果您有任何问题,请告诉我。

~kj

你可以在这里使用Map,它被设计用来应用一个函数"to the first elements of each ... argument, the second elements, the third elements",详情见?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
}

你看到该函数有两个参数,iy(如果你喜欢,可以选择其他名称,例如 dfwidth),并且对于每个数据帧在您的列表中,它修改了第一列 dfl[[i]][, 1] <- ... 。匿名函数的作用是将 str_pad 应用于每个数据帧的第一列

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

但是你看到我们没有将固定值传递给 width 参数,而是 y

回到 MapMap 现在将 str_pad 应用于第一个数据帧,参数为 width = 2,它将 str_pad 应用于第二个数据帧,参数为 width = 3 并且 - 你可能猜到了- 它将 str_pad 应用于列表中的第三个数据框,参数为 width = 4.

参数在代码的最后两行指定为

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

希望对您有所帮助。


数据

(下次考虑创建一个 最小 示例,因为数据帧的行数与问题无关)

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)