R: как найти выбранные файлы в папке на основе совпадения определенного заголовка столбца

#r #list #lapply #filesort #file-move

#r #Список #lapply #сортировка файлов #файл-переместить

Вопрос:

Извините за общий вопрос. Я ищу указатели для сортировки папки с данными, в которой у меня есть множество файлов .txt. Все они имеют разные названия, и для подавляющего большинства из них файлы имеют одинаковое измерение, то есть номера столбцов одинаковы. Однако проблема заключается в том, что некоторые файлы, несмотря на одинаковое количество столбцов, имеют разные имена столбцов. То есть в этих файлах были измерены некоторые другие переменные.

Я хочу отсеять эти файлы, и я не могу этого сделать, просто сравнивая номера столбцов. Есть ли какой-либо метод, с помощью которого я могу передать имя столбца и проверить, сколько файлов в каталоге имеют этот столбец, чтобы я мог удалить их в другую папку?

Обновить:

Я создал фиктивную папку для хранения файлов, отражающих проблему, см. Ссылку ниже, чтобы получить доступ к файлам на моем Google Диске. В этой папке я взял 4 файла, в которых есть проблемные столбцы.

https://drive.google.com/drive/folders/1IDq7BwfQNkGb9y3RvwlLE3FeMQc38taD?usp=sharing

Проблема в том, что код, похоже, может находить файлы, соответствующие критериям выбора, то есть фактическому названию проблемных столбцов, но я не могу извлечь реальный индекс таких файлов в списке. Какие-либо указатели?

 library(data.table)

#read in the example file that have the problem column content
df_var <- read.delim("ctrl_S3127064__3S_DMSO_00_none.TXT", header = T, sep = "t")

#read in a file that I want to use as reference
df_standard <- read.delim("ctrl__S162465_20190111_T8__3S_2DG_3mM_none.TXT", header = T, sep = "t")

#get the names of columns of each file
standar.names <- names(df_standard)
var.names <- names(df_var)

same.titles <- var.names %in% standar.names

dff.titles <- !var.names %in% standar.names

#confirm the only 3 columns of problem is column 129,130 and 131 
mismatched.names <- colnames(df_var[129:131])

#visual check the names of the problematic columns
mismatched.names


# get current working directory and list all files in this directory
wd <- getwd()
files_in_wd <- list.files(wd)

# create an empty list and read in all files from wd
l_files <- list()
for(i in seq_along(files_in_wd)){
  l_files[[i]] <- read.delim(file = files_in_wd[i],
                         sep = "t",
                         header = T,
                         nrows = 2)
}

# get column names of all files
column_names <- lapply(l_files, names)

# get unique names of files
unique_names <- unique(mismatched.names)
unique_names[1]
# decide which files to remove
#here there the "too_keep" returns an integer vector that I don't undestand
#I thought the numbers should represent the ID/index of the elements
#but I have less than 10 files, but the numbers in to_keep are around 1000
#this is probably because it's matching the actually index of the unlisted list
#but if I use to_keep <- which(column_names%in% unique_names[1]) it returns empty vector

to_keep <- which(unlist(column_names)%in% unique_names[1])


#now if I want to slice the file using to_keep the files_to_keep returns NA NA NA
files_to_keep <- files_in_wd[to_keep]

#once I have a list of targeted files, I can remove them into a new folder by using file.remove
library(filesstrings)
file.move(files_to_keep, "C:/Users/mli/Desktop/weeding/need to reanalysis" )
  

Комментарии:

1. Взгляните на пакет fs: tidyverse.org/blog/2018/01/fs-1.0.0

2. Привет @mharinga, похоже, я не нашел инструментов в этом пакете для этой конкретной проблемы

Ответ №1:

Если вы можете отличить файлы, которые вы хотели бы сохранить, от тех, которые вы хотели бы удалить, в зависимости от имен столбцов, вы могли бы использовать что-то в этом роде:

 # set working directory to folder with generic text files
setwd("C:/Users/tester/Desktop/generic-text-files")

# get current working directory and list all files in this directory
wd <- getwd()
files_in_wd <- list.files(wd)

# create an empty list and read in all files from wd
l_files <- list()
for(i in seq_along(files_in_wd)){
  l_files[[i]] <- read.delim(file = files_in_wd[i],
                             sep = ';',
                             header = T,
                             nrows = 2)
}

# get column names of all files
column_names <- lapply(l_files, names)
# get unique names of files
unique_names <- unique(column_names)
# decide which files to keep
to_keep <- which(column_names %in% unique_names[1])

files_to_keep <- files_in_wd[to_keep]
  

Если у вас много файлов, вам, вероятно, следует избегать цикла или просто прочитать заголовок соответствующего файла.

редактировать после вашего комментария:

  • при добавлении nrows = 2 код считывает только первые 2 строки заголовок.
  • Я предполагаю, что первый файл в папке имеет структуру, которую вы хотели бы сохранить, поэтому column_names проверяется на соответствие unique_names[1] .
  • files_to_keep содержит имена файлов, которые вы хотели бы сохранить
  • вы можете попробовать запустить это для подмножества ваших данных и посмотреть, работает ли это, и беспокоиться об эффективности позже. Я думаю, что векторизованный подход может работать лучше.

редактировать: этот код работает с вашими фиктивными данными.

 library(filesstrings)

# set working directory to folder with generic text files
setwd("C:/Users/tester/Desktop/generic-text-files/dummyset")

# get current working directory and list all files in this directory
wd <- getwd()
files_in_wd <- list.files(wd)

# create an empty list and read in all files from wd
l_files <- list()
for(i in seq_along(files_in_wd)){
  l_files[[i]] <- read.delim(file = files_in_wd[i],
                             sep = "t",
                             header = T,
                             nrows = 2,
                             encoding = "UTF-8",
                             check.names = FALSE
                            )
}

# get column names of all files
column_names <- lapply(l_files, names)
# decide which files to keep
to_keep <- column_names[[1]] # e.g. column names of file #1 are ok

# check if the other files have the same header:
df_filehelper <- data.frame('fileindex' = seq_along(files_in_wd),
  'filename' = files_in_wd,
  'keep' = NA)

for(i in 2:length(files_in_wd)){
  df_filehelper$keep[i] <- identical(to_keep, column_names[[i]])
}

df_filehelper$keep[1] <- TRUE # keep the original file used for selecting the right columns

# move files out of the current folder:
files_to_move <- df_filehelper$filename[!df_filehelper$keep] # selects file that are not to be kept

file.move(files_to_move, "C:/Users/tester/Desktop/generic-text-files/dummyset/testsubfolder/")
  

Комментарии:

1. Я думаю, ваша идея сработает. И, как вы указали, папка огромная, 200000K файлов, размером несколько ТБ. Как мне просто прочитать заголовок? И если я правильно понимаю, код последней строки to_keep возвращает только список, каждый элемент представляет собой файл, соответствующий выбранному имени. Как мне вывести их в папку?

2. Я действительно надеюсь, что смогу протестировать это на выходных, но у нас тупое отключение сервера из-за тестирования питания в больнице. Возможно, мне придется протестировать это в понедельник и связаться с вами, если это сработает или нет. извинения.

3. Я тестирую код, который вы предлагаете. Я проделал некоторую предварительную обработку, чтобы идентифицировать разные столбцы. все файлы имеют одинаковые 131 столбец, разница заключается в последних 3 столбцах 129, 130 и 133, которые имеют разные имена. Я создал фиктивную небольшую папку, однако последние 2 строки кода, to_keep <- which () всегда возвращает пустое значение. неважно, соответствует ли я всем 3 именам столбцов или только 1. Но я точно знаю, что все файлы в папке содержат все 3 заголовка…

4. Видел какой-то пост и протестировал, я думаю, нам нужно отменить список () column_names.

5. Прошу прощения за раздражение, и, честно говоря, я только что понял, какой я тупой новичок, в вашем цикле удаления чтения, поскольку я знаю, что все проблемы возникают в столбце 129-130, все, что мне нужно, это добавить [,129:131] затем мне сошли с рук все проблемы с номерами столбцов, и теперьбольший набор работает нормально

Ответ №2:

Из-за большого количества и размера файлов, возможно, стоит рассмотреть альтернативы R, например, в bash:

 for f in ctrl*.txt
do
  if [[ "$(head -1 ctrl__S162465_20190111_T8__3S_2DG_3mM_none.txt | md5)" != "$(head -1 $f | md5)" ]]
    then echo "$f"
  fi
done
  

Эта команда сравнивает имена столбцов «хорошего файла» с именами столбцов каждого файла и выводит имена файлов, которые не совпадают.

Комментарии:

1. Спасибо за ваше время. Сначала я должен извиниться за то, что я такой новичок, что basic R — это все, что я знаю… Я играл с ответом тестировщиков и, изменив столбцы для чтения и фокусировки, я заставил его работать. Но я обязательно прочитаю ваше предложение.