用于将数据框中的字符数据转换为数字的 For 循环

For loop for converting character data to numeric in a data frame

我有 50 个数据框(每个名称不同)和 10 个(同名)气候数据列。前 5 列虽然是数字,但它们的 class 是“字符”。其余 4 列已经是正确的 class(数字),最后一列(名为 'wind dir')是字符 class,因此不需要更改。

我尝试了两种方法来转换所有 50 个数据框中的那 5 列的 class,但没有任何效果。

第一种方式)首先我用这 50 个数据框的名称创建了一个向量,并将其命名为 onomata.

其次我创建了一个向量col_numbers2 <- c(1:5),其中包含我要转换的列数。

然后我写了下面的代码:

for(i in onomata){
  i[col_numbers2] <- sapply(i[col_numbers2], as.numeric)
}

检查前五列的 class,我发现没有任何变化。 (执行代码后无报错)

2nd way)然后我尝试使用带有for循环的dplyr包,代码如下:

for(i in onomata){
 i <- i %>%
  mutate_at(vars(-`wind_dir`),as.numeric)

在这种情况下,我排除了字符列,并将 mutate 函数应用于整个数据框,但我收到一条错误消息:

UseMethod("tbl_vars") 错误: 没有适用于 'tbl_vars' 的方法应用于 class“字符”

的对象

你认为我做错了什么?

谢谢

原始数据table(当我对每个 txt 文件使用 read.table() 时得到的结果:

date Time Tdry Humidity Wind_velocity Wind_direction Wind_gust
02/01/15 02:00 2.4 77.0 6.4 WNW 20.9
02/01/15 03:00 2.3 77.0 11.3 NW 30.6
02/01/15 04:00 2.3 77.0 9.7 NW 20.9
02/01/15 05:00 2.3 77.0 11.3 NW 30.6
02/01/15 06:00 2.3 78.0 9.7 NW 19.3
02/01/15 07:00 2.2 79.0 12.9 NNW 35.4
02/01/15 08:00 2.4 79.0 8.0 NW 14.5
02/01/15 09:00 2.6 79.0 8.0 WNW 20.9

我在第 1 列和第 2 列(日期、时间)中拆分数据后的数据:

day month year Hour Minutes Tdry Humidity Wind_velocity Wind_direction Wind_gust
02 01 15 02 00 2.4 77.0 6.4 WNW 20.9
02 01 15 03 00 2.3 77.0 11.3 NW 30.6
02 01 15 04 00 2.3 77.0 9.7 NW 20.9
02 01 15 05 00 2.3 77.0 11.3 NW 30.6
02 01 15 06 00 2.3 78.0 9.7 NW 19.3
02 01 15 07 00 2.2 79.0 12.9 NNW 35.4
02 01 15 08 00 2.4 79.0 8.0 NW 14.5
02 01 15 09 00 2.6 79.0 8.0 WNW 20.9

也许以下代码可以提供帮助。
首先,获取带有 list.files 的文件名。其次,使用 lapply 将它们全部读完。如果 read.table 不是合适的功能,请阅读 help("read.table"),它与 read.csvread.csv2 等的同一页。然后,强制所有 [= 的前 5 列=20=] 一次性转换成数字。

filenames <- list.files(path = "your_directory", pattern = "\.txt")
onomata <- lapply(filenames, read.table)

onomata <- lapply(onomata, function(X){
  X[1:5] <- lapply(X[1:5], as.numeric)
  X
})

这里有两种可能的方法。两者都依赖于将所有文件放入数据帧列表中(在下面的示例中称为 df_list)。为此,您可以使用 mget()(例如:mget(onomata)list.files())。

完成后,您可以使用 lapply(或 mapply)遍历所有数据帧。

解决方案 1

要转换您的数据,我建议您首先将其转换为 POSIXct 格式,然后提取相关元素以生成所需的列。

# create a custom function that transforms each dataframe the way you want
fun_split_datehour <- function(df){
  
  df[, "datetime"] <- as.POSIXct(paste(df$date, df$hour), format = "%d/%m/%Y %H:%M") # create a POSIXct column with info on date and time
  
  # Extract elements you need from the date & time column and store them in new columns
  df[,"year"] <- as.numeric(format(df[, "datetime"], format = "%Y"))
  df[,"month"] <- as.numeric(format(df[, "datetime"], format = "%m"))
  df[,"day"] <- as.numeric(format(df[, "datetime"], format = "%d"))
  df[,"hour"] <- as.numeric(format(df[, "datetime"], format = "%H"))
  df[,"min"] <- as.numeric(format(df[, "datetime"], format = "%M"))
  
  return(df)
}

# use this function on each dataframe of your list
lapply(df_list, FUN = fun_split_datehour)

改编自Split date data (m/d/y) into 3 separate columns (this answer)

数据:

# two dummy dataframe, date and hour format does not matter, you can tell as.POSIXct what to expect using format argument (see ?as.POSIXct)
df1 <- data.frame(date = c("02/01/2010", "03/02/2010", "10/09/2010"),
                 hour = c("05:32", "08:20", "15:33"))
df2 <- data.frame(date = c("02/01/2010", "03/02/2010", "10/09/2010"),
                  hour = c("05:32", "08:20", "15:33"))
# you can replace c("df1", "df2") with onomata:  df_list <- mget(onomata)
df_list <- mget(c("df1", "df2"))

输出:

> lapply(df_list, FUN = fun_split_datehour)
$df1
        date hour            datetime year month day min
1 2010-01-02    5 2010-01-02 05:32:00 2010     1   2  32
2 2010-02-03    8 2010-02-03 08:20:00 2010     2   3  20
3 2010-09-10   15 2010-09-10 15:33:00 2010     9  10  33

$df2
        date hour            datetime year month day min
1 2010-01-02    5 2010-01-02 05:32:00 2010     1   2  32
2 2010-02-03    8 2010-02-03 08:20:00 2010     2   3  20
3 2010-09-10   15 2010-09-10 15:33:00 2010     9  10  33

并且列 yearmonthdayhourmin 是数字。您可以使用 str(lapply(df_list, FUN = fun_split_datehour)).

检查

注:看着, you might find 有用。另外,使用POSIXct格式,如果你想作图,编排,

,可以节省你的时间

解决方案 2

如果你不想使用 POSIXct,你可以这样做:

# Dummy data changed to match you situation with already splited date
dfa <- data.frame(day = c("02", "03", "10"),
                  hour = c("05", "08", "15"))
dfb <- data.frame(day = c("02", "03", "10"),
                  hour = c("05", "08", "15"))
df_list <- mget(c("dfa", "dfb"))

# Same thing, use lapply() to go through each dataframe of the list and apply() to use as.numeric on the wanted columns
lapply(df_list, FUN = function(df){as.data.frame(apply(df[1:2], 2, as.numeric))}) # change df[1:2] to select columns you want to convert in your actual dataframes