#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 — это все, что я знаю… Я играл с ответом тестировщиков и, изменив столбцы для чтения и фокусировки, я заставил его работать. Но я обязательно прочитаю ваше предложение.