【问题标题】:Acquiring 2nd Element of Uneven List获取不均匀列表的第二个元素
【发布时间】:2019-08-07 02:17:10
【问题描述】:

(关于 R 中列表的问题)

我正在处理一个非常大的数据集,其中我的日期列采用以下两种形式之一:

  • 日期类型 1:“MM/DD/YYYY HH:MM:SS AM”
  • 日期类型 2:“MM/DD/YYYYHH:MM:SS AM - MM/DD/YYYY HH:MM:SS AM”

我需要根据(类型 2)中是否有破折号来拆分此列,并将它们放在两列(“日期 1”和“日期 2”)中。如果我遇到具有类型 1 日期的行,则日期将简单地占据“日期 1”,而“日期 2”将只是 NA

这就是我要找的东西——转换一些看起来像这样的东西:

c(
    rep("8/20/2018 9:18:45 AM", 15),
    rep("8/20/2018 9:18:45 AM - 8/12/2018 9:18:45 AM", 15)
  )

对此:

data.frame(
  Date1 = c(rep("8/15/2018 9:18:45 AM", 15), rep("8/20/2018 9:18:45 AM", 15)),
  Date2 = c(rep(NA, 15), rep("8/12/2018 9:18:45 AM", 15))
)

# output
# Date1                Date2
# 1  8/15/2018 9:18:45 AM                 <NA>
#   2  8/15/2018 9:18:45 AM                 <NA>
#   3  8/15/2018 9:18:45 AM                 <NA>
#   4  8/15/2018 9:18:45 AM                 <NA>
#   5  8/15/2018 9:18:45 AM                 <NA>
#   6  8/15/2018 9:18:45 AM                 <NA>
#   7  8/15/2018 9:18:45 AM                 <NA>
#   8  8/15/2018 9:18:45 AM                 <NA>
#   9  8/15/2018 9:18:45 AM                 <NA>
#   10 8/15/2018 9:18:45 AM                 <NA>
#   11 8/15/2018 9:18:45 AM                 <NA>
#   12 8/15/2018 9:18:45 AM                 <NA>
#   13 8/15/2018 9:18:45 AM                 <NA>
#   14 8/15/2018 9:18:45 AM                 <NA>
#   15 8/15/2018 9:18:45 AM                 <NA>
#   16 8/20/2018 9:18:45 AM 8/12/2018 9:18:45 AM
# 17 8/20/2018 9:18:45 AM 8/12/2018 9:18:45 AM
# 18 8/20/2018 9:18:45 AM 8/12/2018 9:18:45 AM
# 19 8/20/2018 9:18:45 AM 8/12/2018 9:18:45 AM
# 20 8/20/2018 9:18:45 AM 8/12/2018 9:18:45 AM
# 21 8/20/2018 9:18:45 AM 8/12/2018 9:18:45 AM
# 22 8/20/2018 9:18:45 AM 8/12/2018 9:18:45 AM
# 23 8/20/2018 9:18:45 AM 8/12/2018 9:18:45 AM
# 24 8/20/2018 9:18:45 AM 8/12/2018 9:18:45 AM
# 25 8/20/2018 9:18:45 AM 8/12/2018 9:18:45 AM
# 26 8/20/2018 9:18:45 AM 8/12/2018 9:18:45 AM
# 27 8/20/2018 9:18:45 AM 8/12/2018 9:18:45 AM
# 28 8/20/2018 9:18:45 AM 8/12/2018 9:18:45 AM
# 29 8/20/2018 9:18:45 AM 8/12/2018 9:18:45 AM
# 30 8/20/2018 9:18:45 AM 8/12/2018 9:18:45 AM

我希望列表的第一个子元素占据Date1 列,第二个子元素(如果存在)占据Date2 列。如果没有第二个元素,我希望Date2 行是NA

我的第一次尝试是创建一个使用条件的新列表。如果子元素的长度只有一个,我创建第二个子元素,并将其设置为NA

dates = c(
  c(
    rep("8/20/2018 9:18:45 AM", 15),
    rep("8/20/2018 9:18:45 AM - 8/12/2018 9:18:45 AM", 15)
  )
)


# create the date split. Split the text based on the dash 
dates_split = strsplit(dates, " - ")
# note where the correct dates are. date_split[[15]] as one sub element and date_split[[16]] has two
dates_split[[15]];dates_split[[16]]

# so far so good






# create a conditional where if there is only one date (one sub element), set the second sub element to zero.
for(i in 1:length(dates_split)){
  if(length(dates_split[i]) == 1){
    dates_split[[i]][2] = NA
  } else {}
}

# the above loop does not behave as expected. The dates_split[[16]][2] is now gone (it turned to NA)






# create a vector for Date1 and Date2
Date1 = unlist(lapply(dates_split, "[[", 1))
Date2 = unlist(lapply(dates_split, "[[", 2))

# put each date type in their appropriate column
date_df = data.frame(
  Date1 = Date1,
  Date2 = Date2
)

# second column is all NA's. Where did the second sub elements go?

我之前在较小数据集上的脚本做了这样的事情来解决它:

dates = strsplit(dates, " - ")

# this takes forever to do. Is there a way to do this without using a loop??
for(i in 1:nrow(dates_split)){
  date_df$Date1 = dates[[i]][1]
  date_df$Date2 = dates[[i]][2]
}

上面的效率不是很高。真实的数据集超过一百万行,因此加载需要很长时间。

对于如何修改此步骤,以便我为第二个子元素创建 NA 而不会无意中将所有内容变成 NA,是否有任何建议?

# create a conditional where if there is only one date (one sub element), set the second sub element to zero.
for(i in 1:length(dates_split)){
  if(length(dates_split[i]) == 1){
    dates_split[[i]][2] = NA
  } else {}
}

# the above loop does not behave as expected. The dates_split[[16]][2] is now gone (it turned to NA)

谢谢!

【问题讨论】:

    标签: r string list split


    【解决方案1】:

    首先,回答以下问题

    对于如何修改此步骤以便我创建 NA 为第二个子元素而不会无意中转动一切 进入北美?

    只需在for 循环的第二行将[i] 替换为[[i]]

    其次,我对您的代码进行了一些修改并测试了速度。 1000 万个数据点大约需要 15 秒。所以它非常快。我试图用lapply 替换for 循环,但这并没有提高速度。现在你可以使用data.table 包加速它(也许显着),但有一些学习曲线。这是用于测试的完整代码,以查看是否一切都按您的预期工作。

    # how many times to repeat dates (five million for testing)
    rep.num = 5000000
    
    # create dummy dates
    dates = c(
        rep("8/20/2018 9:18:45 AM", rep.num),
        rep("8/20/2018 9:18:45 AM - 8/12/2018 9:18:45 AM", rep.num)
    )
    
    # create the date split. Split the text based on the dash 
    # using fixed = T here results in significant speed increase
    dates_split <- strsplit(dates, " - ", fixed = T)
    
    # note where the correct dates are. date_split[[rep.num]] as one sub element and date_split[[rep.num + 1]] has two
    dates_split[[rep.num]]
    dates_split[[rep.num + 1]]
    dates_split[[rep.num + 1]][1]
    dates_split[[rep.num + 1]][2]
    
    # create a conditional where if there is only one date (one sub element), set the second sub element to zero.
    for(i in 1:length(dates_split)){
      if(length(dates_split[[i]]) == 1){
        dates_split[[i]][2] = NA
      }
    }
    
    # put each date type in their appropriate column
    date_df = data.frame(
      Date1 = sapply(dates_split, "[[", 1),
      Date2 = sapply(dates_split, "[[", 2)
    )
    

    【讨论】:

    • 谢谢!我很感激。看起来在我的原始代码中我没有正确构造我的 if-then 语句。我不小心写了if(length(dates[[i]] == 1)){...}。因此,它将每个实例视为T,并将所有内容设置为NA。但我确实学会了使用sapply() 而不是取消列出lapply()。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2019-10-23
    • 1970-01-01
    • 2017-02-11
    • 1970-01-01
    • 2019-11-25
    • 1970-01-01
    • 1970-01-01
    • 2011-02-17
    相关资源
    最近更新 更多