首页 > 解决方案 > 在数据框列表中,用前导零填充一个变量(最好使用 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")

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

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

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

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

seq <- c(2,3,4)

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

~kj

标签: rlapplynumber-formattingstringrpad

解决方案


您可以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
}

您会看到该函数有两个参数,iand y(如果您喜欢,请选择其他名称,例如dfand 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) 

我希望这有帮助。


数据

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

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)

推荐阅读