如何使用do.call()读取特定行?

时间:2019-05-14 18:40:44

标签: r data.table do.call

我正在使用do.call()命令读取一个csv文件列表,以将所有数据点保存在一个csv文件中。我一直在使用以下内容:

files = list.files(path = "G:/SafeGraph201708MidWest",
                     pattern = "*.csv",
                     recursive = TRUE,
                     full.names = TRUE)

library(data.table)
  DT = do.call(rbind, lapply(files, fread))

我要读取特定的行,而不是读取每个文件中的所有行。尤其是在此范围内的那些:

Data <- filter(DT, longitude >= -86.97 & longitude <= -86.78, 
                 latitude >= 40.35 & latitude <= 40.49)

有没有一种方法可以使用do.call()完成?期待很快的答复。谢谢!

3 个答案:

答案 0 :(得分:3)

有几种解决此问题的策略。您可以使用lapply将所有数据导入列表,然后根据您的过滤器从每个列表元素中过滤掉。您将使用data.table::rbindlist来制作最终的data.table。另一步骤是一步完成此操作,例如(显然,未经测试)

library(data.table)

files = list.files(path = "G:/SafeGraph201708MidWest",
                   pattern = "*.csv",
                   recursive = TRUE,
                   full.names = TRUE)

xy <- lapply(files, FUN = function(x) {
  out <- fread(x)
  out <- filter(out, longitude >= -86.97 & longitude <= -86.78, 
                latitude >= 40.35 & latitude <= 40.49)
  out
})

xy <- rbindlist(xy)

答案 1 :(得分:1)

假设您使用Windows PC并至少安装了Microsoft Office 2007+,请考虑直接使用JET / ACE SQL引擎(.dll文件)直接查询CSV,这是MS Access的引擎。

以下包括使用Access或Excel的两个连接字符串。两种版本都可以使用,并且文件确实需要存在,但是除了连接到ACE之外,从不使用。连接后,即可从相同或不同的路径查询CSV文件。

library(odbc)

# VERIFY AVAILABLE DSNs AND DRIVERS
odbcListDataSources()

# DSN VERSIONS
conn <- dbConnect(odbc::odbc(), DSN ="MS Access Database;DBQ=C:\\Path\\To\\Access.accdb;");
conn <- dbConnect(odbc::odbc(), DSN ="Excel Files;DBQ=C:\\Path\\To\\Excel.xlsx;");

# DRIVER VERSIONS
conn <- dbConnect(odbc::odbc(), 
                  .connection_string = "Driver={Microsoft Access Driver (*.mdb, *.accdb)};DBQ=C:\\Path\\To\\Access.accdb;");    
conn <- dbConnect(odbc::odbc(), 
                  .connection_string ="Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};DBQ=C:\\Path\\To\\Excel.xlsx;");

# CSV QUERY
df <- dbGetQuery(conn, "SELECT t.* 
                        FROM [text;database=C:\\Path\\To\\CSV_Folder].Name_of_File.csv AS t 
                        WHERE t.longitude BETWEEN -86.97 AND -86.78
                          AND t.latitude BETWEEN 40.35 AND 40.49;")    
head(df)

dbDisconnect(conn)

然后循环:

files = list.files(path = "G:/SafeGraph201708MidWest",
                   pattern = "*.csv",
                   recursive = TRUE,
                   full.names = TRUE)    

df_list <- lapply(files, function(f)    
    df <- dbGetQuery(conn, 
                     paste0("SELECT t.* ",
                            " FROM [text;database=G:\\SafeGraph201708MidWest].", f, " AS t ",
                            " WHERE t.longitude BETWEEN -86.97 AND -86.78", 
                            "   AND t.latitude BETWEEN 40.35 AND 40.49;")
                    )    
)

final_dt <- rbindlist(df_list)

答案 2 :(得分:0)

您可以使用data.table::fread()中的功能来执行命令并“读取”他的结果。

我假设您正在使用Windows,因此可以在命令提示符下访问findstr功能。

因此,如果您可以构建要在要提取的行上“命中”的正则表达式,则可以在将整个文件读入R之前过滤需要的行。这(可能)是较大文件上的节省内存的存储,并可能大大加快您的工作流程。

样本数据

lat的说法coords.csv看起来像这样:

id,latitude,longitude
1,10,11
2,11,12
3,12,13
4,13,14
5,14,15

在此示例中,您要提取线的纬度在12和14之间,经度在11和13之间

代码

#build a list of files (I created only one)
#make sure you use the full path (not relative)
x <- list.files( path = "C:/folder", pattern = "coord.csv", full.names = TRUE )

#build reges that only hits on rows with:
#  latitude 12-14
#  longitude 11-13
pattern = "^[0-9],1[2-4],1[1-3]$"

#read the file(s), extract the lines with match the regex-pattern 
#and bind the resuklt to a data.table
rbindlist( lapply( x, function(x) { 
  fread( cmd = paste0( "findstr /R ", pattern, " ", x ), header = FALSE ) 
} ) )

输出

    V1 V2 V3
 1:  3 12 13