Удалить первые 10 и последние 10 значений

Путь Ruby заключается в том, чтобы подделать его с запутанными хаками, которые заставят некоторых пользователей задаться вопросом: «Как в fuck это даже работает?», в то время как менее любопытный просто запоминает синтаксис, необходимый для использования этой вещи. Если вы когда-либо использовали Rake или Rails, вы видели такие вещи.

Вот такой хак:

def mlet(name,func)
  my_class = (Class.new do
                def initialize(name,func)
                  @name=name
                  @func=func
                end
                def method_missing(methname, *args)
                  puts "method_missing called on #{methname}"
                  if methname == @name
                    puts "Calling function #{@func}"
                    @func.call(*args)
                  else
                    raise NoMethodError.new "Undefined method `#{methname}' in mlet"
                  end
                end
              end)
  yield my_class.new(name,func)
end

Что это значит, который создает класс и передает его блоку. Класс использует method_missing, чтобы притворяться, что у него есть метод с именем, которое вы выбрали. Он «реализует» метод, вызывая лямбда, которую вы должны предоставить. Назвав объект однобуквенным именем, вы можете свести к минимуму количество лишнего ввода, которое оно требует (что то же самое, что Rails делает в schema.rb). mlet назван в честь формы Common Lisp flet, за исключением случаев, когда f обозначает «функцию», m обозначает «метод».

Вы используете его следующим образом:

def outer
   mlet :inner, ->(x) { x*2 } do |c|
     c.inner 12
   end
end

Можно создать аналогичное приспособление, которое позволяет определять множество внутренних функций без дополнительного вложения, но для этого требуется еще более уродливый взлом такого рода, который вы можете найти в реализации Rake или Rspec. Выяснение того, как работает Rspec let!, даст вам долгий путь к созданию такой ужасной мерзости.

1
задан PoGibas 15 January 2019 в 15:11
поделиться

3 ответа

Использование data.table:

library(data.table)
idt <- as.data.table(iris)
idt[, .SD[11:(.N-10)], Species]

Та же логика в base R:

do.call(
  rbind, 
  lapply(
    split(iris, iris[["Species"]]), 
    function(x) x[11:(nrow(x)-10), ]
  )
)
0
ответ дан sindri_baldur 15 January 2019 в 15:11
поделиться

Здесь решение с dplyr.

В моем примере я вырезал только первое и последнее значения. (вы можете изменить его, изменив 2 на любое число в filter).

Идея состоит в том, чтобы добавить после group_by id номер строки для каждого наблюдения, начиная сверху (n) и наоборот снизу (n1), тогда вы просто отфильтруете. [119 ]

library(dplyr)

data %>% 
  group_by(id) %>% 
  mutate(n=1:n(),
         n1 = n():1) %>% # n and n1 are the row numbers
  filter(n >= 2,n1 >= 2) %>%  # change 2 with 10, or whatever
# filter() keeps only the rows that you want
  select(-n, -n1) %>%
  ungroup()
# # A tibble: 4 x 2
# id value
# <dbl> <int>
# 1     1     6
# 2     1     8
# 3     2     1
# 4     2     2

Данные:

set.seed(123)
data <- data.frame(id = c(rep(1,4), rep(2,4)), value=sample(8))
data
#   id value
# 1  1     3
# 2  1     6
# 3  1     8
# 4  1     5
# 5  2     4
# 6  2     1
# 7  2     2
# 8  2     7
0
ответ дан RLave 15 January 2019 в 15:11
поделиться

Если вы знаете, что у вас всегда есть более 20 точек данных по корове, вы можете сделать следующее, как показано в наборе данных iris:

library(dplyr)

dim(iris)
# [1] 150   5

iris_trimmed <-
  iris %>%
  group_by(Species) %>%
  slice(11:(n()-10)) %>%
  ungroup()

dim(iris_trimmed)
# [1] 90  5

По вашим данным:

res <-
  your_data %>%
  group_by(Cow) %>%
  slice(11:(n()-10)) %>%
  ungroup()
[116 ] В базе R вы можете сделать:

iris_trimmed <- do.call(
  rbind, 
  lapply(split(iris, iris$Species),
         function(x) head(tail(x,-10),-10)))

dim(iris_trimmed)
# [1] 90  5
0
ответ дан Moody_Mudskipper 15 January 2019 в 15:11
поделиться
Другие вопросы по тегам:

Похожие вопросы: