2016-10-20 17 views
0

У меня есть следующий набор данных (ds1) в файле CSV, который включает в себя имя класса и соответствующие ошибки. Я намерен извлечь или фильтровать имя пакета из данных с числом ошибок, равным 2, используя R-скрипт.Извлечение имени пакета из полностью определенных имен классов с использованием сценариев R

Class        Faults 

org.apache.tools.ant.taskdefs.Definer 2 
org.apache.tools.ant.taskdefs.Definer 2 
org.apache.tools.ant.taskdefs.Delete 1 
org.apache.tools.ant.taskdefs.Deltree 2 
org.apache.tools.ant.taskdefs.DependSet 2 
org.apache.tools.ant.taskdefs.DependSet 2 
org.apache.tools.ant.taskdefs.DependSet 2 
org.apache.tools.ant.taskdefs.Ear 2 
org.apache.tools.ant.taskdefs.Ear 2 
org.apache.tools.ant.taskdefs.Echo 1 
org.apache.tools.ant.Exec 2 
org.apache.tools.ant.Exec 2 

Я написал следующий код, но он не дает желаемых результатов

dschanged<- subset(ds1, grep("/^([^\\.]+)/", class) & Faults==2) 

Технически, я требую правильное регулярное выражение, чтобы вытащить строку перед последней точкой (.), Чтобы сгенерировать следующий вывод.

org.apache.tools.ant.taskdefs  2 
org.apache.tools.ant.taskdefs  2 
org.apache.tools.ant.taskdefs  2 
org.apache.tools.ant.taskdefs  2 
org.apache.tools.ant.taskdefs  2 
org.apache.tools.ant.taskdefs  2 
org.apache.tools.ant.taskdefs  2 
org.apache.tools.ant.taskdefs  2 
org.apache.tools.ant    2 
org.apache.tools.ant    2 
+2

Будет ли «grepl» более уместным? – r2evans

+0

Можете ли вы разрешить это с помощью 'grepl'? –

+0

У '' /^([^\\.]+)/ '' есть одна серьезная проблема: вы используете разделители регулярных выражений '/', которые не должны использоваться в функциях R regex. Кроме того, когда вы избегаете символа '.' В классе символов, вы делаете его совместимым только с PCRE (больше не совместимым с TRE). Однако, чтобы получить строку перед последней точкой, вам понадобится ''^(. *) \\. "' (Тогда у вас есть захваченное значение внутри группы 1) или PCRE один '' ^. * (? = \ \.) "' (с 'perl = TRUE'). –

ответ

1

grepgrepl) не подходят для этого: вы не фильтрации на основе текстового содержимого. Вы (а) фильтруете на основе Faults и (b) меняете текст в Class.

Данные:

ds1 <- structure(list(Class = c("org.apache.tools.ant.taskdefs.Definer", "org.apache.tools.ant.taskdefs.Definer", "org.apache.tools.ant.taskdefs.Delete", "org.apache.tools.ant.taskdefs.Deltree", "org.apache.tools.ant.taskdefs.DependSet", "org.apache.tools.ant.taskdefs.DependSet", "org.apache.tools.ant.taskdefs.DependSet", "org.apache.tools.ant.taskdefs.Ear", "org.apache.tools.ant.taskdefs.Ear", "org.apache.tools.ant.taskdefs.Echo", "org.apache.tools.ant.Exec", "org.apache.tools.ant.Exec"), 
         Faults = c(2L, 2L, 1L, 2L, 2L, 2L, 2L, 2L, 2L, 1L, 2L, 2L)), 
       .Names = c("Class", "Faults"), class = "data.frame", row.names = c(NA, -12L)) 

Фильтр по Faults (вы уже это). Вам нужна только одна из этих двух команд, они оба делают то же самое; основные отличия заключаются в удобочитаемости (личном предпочтении) и производительности (вторая, в данном случае, занимает около 35% меньше времени, хотя, поскольку они оба измеряются в микросекундах, кажется, что глупо конкурировать).

ds2 <- subset(ds1, Faults == 2) 
ds2 <- ds1[ds1$Faults == 2,] 

Update Class удалить последнее слово (и точка):

ds2$Class <- gsub("\\.[^.]*$", "", ds2$Class) 
ds2 
#       Class Faults 
# 1 org.apache.tools.ant.taskdefs  2 
# 2 org.apache.tools.ant.taskdefs  2 
# 4 org.apache.tools.ant.taskdefs  2 
# 5 org.apache.tools.ant.taskdefs  2 
# 6 org.apache.tools.ant.taskdefs  2 
# 7 org.apache.tools.ant.taskdefs  2 
# 8 org.apache.tools.ant.taskdefs  2 
# 9 org.apache.tools.ant.taskdefs  2 
# 11   org.apache.tools.ant  2 
# 12   org.apache.tools.ant  2 

Примечание: это также может быть сделано с sub вместо gsub, но последний мой первый-достигните, так как большинство мои работы связаны с большими и повторяющимися регулярными выражениями. Главный (? Только) различие между ними состоит в том, что:

'sub' and 'gsub' perform replacement of the first and all matches respectively

(от ?sub).

Я не знаю инструмента, который делает как фильтрация и изменение в одной команде (хотя возможно data.table делает, я не знаю).

Аналогично решению @ egnha (то использует magrittr), вот один с помощью dplyr, что многие люди утверждают, очень легко читать и адаптироваться (при потенциальной стоимости исполнения):

library(dplyr) 
ds2 <- ds1 %>% 
    filter(Faults == 2) %>% 
    mutate(Class = gsub("\\.[^.]*$", "", Class)) 

Поскольку я упомянул производительность, вот сравнение:

microbenchmark(indexing = { ds2 <- ds1[ds1$Faults == 2,]; ds2$Class <- gsub("\\.[^.]*$", "", ds2$Class) }, 
       subset = { ds2 <- subset(ds1, Faults == 2) ; ds2$Class <- gsub("\\.[^.]*$", "", ds2$Class) }, 
       dplyr = { ds1 %>% filter(Faults == 2) %>% mutate(Class = gsub("\\.[^.]*$", "", Class)) }) 
# Unit: microseconds 
#  expr  min  lq  mean median  uq  max neval 
# indexing 71.841 87.7045 109.4496 104.2975 120.7075 269.493 100 
# subset 102.473 115.6020 147.0108 139.1230 165.5620 287.726 100 
#  dplyr 1067.030 1156.3745 1323.1174 1225.4805 1351.2920 4270.308 100 

Для записи dplyr используется таким образом, не часто эта скорость бедных по сравнению с другими методами. Обычно не быстрее, но это не часто на порядок медленнее.

+0

Thanks @ r2evans –

+0

это сработало для меня –

+0

@ r2evans - Nice benchmarking. Я бы не ожидал, что dplyr будет настолько медленнее в этом случае. Любое понимание того, почему? – egnha

0

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

library(magrittr) # Provides pipe operator `%>%` 

dschanged <- subset(ds1, Faults == 2) 
dschanged$Class <- dschanged$Class %>% 
        strsplit(split = "[.]") %>% 
        sapply(function(x) head(x, -1L) %>% paste(collapse = ".")) 

Обратите внимание, что строки без точек будут преобразованы в пустые строки. Это также довольно немного медленнее, чем решение, предлагаемое @ r2evans.

+0

Вы действительно должны включать в себя не-базовые библиотеки с вашим решением. Не все достаточно хорошо владеют, чтобы знать, что это использует «magrittr». – r2evans

+0

@ r2evans - Я бы забыл это, спасибо. Сделано изменение. – egnha

0

Я не думаю, что вы ищете фильтрацию на основе имени класса. Просто сделайте это за 2 шага.

# Filter 
dschanged <- ds1[ds1$Faults == 2,] 
# Extract package name 
dschanged$class <- sub('(.*)[.](.*)','\\1',dschanged$class)