Группировать данные по уровню фактора, а затем преобразовывать в фрейм данных с именами уровней? - PullRequest
0 голосов
/ 14 декабря 2018

Моя проблема в том, что я не могу ее решить:

Данные:

df <- data.frame(f1=c("a", "a", "b", "b", "c", "c", "c"), 
                 v1=c(10, 11, 4, 5, 0, 1, 2))

data.frame:f1 is factor
  f1 v1
  a   10
  a   11
  b   4
  b   5
  c   0
  c   1   
  c   2
 # What I want is:(for example, fetch data with the number of element of some level == 2, then to data.frame)
  a   b
 10   4
 11   5  

Заранее спасибо!

Ответы [ 5 ]

0 голосов
/ 14 декабря 2018

Вот решение, использующее unstack:

unstack(
  droplevels(df[ave(df$v1, df$f1, FUN = function(x) length(x) == 2)==1,]),
  v1 ~ f1)
#    a b
# 1 10 4
# 2 11 5

Вариант, аналогичный решению @ thelatemail:

data.frame(Filter(function(x) length(x) == 2, unstack(df,v1 ~ f1)))

My tidyverse решениебудет:

library(tidyverse)
df                  %>%
  group_by(f1)      %>%
  filter(n() == 2)  %>%
  mutate(i = row_number()) %>%
  spread(f1, v1)   %>%
  select(-i)
# # A tibble: 2 x 2
#       a     b
# * <dbl> <dbl>
# 1    10     4
# 2    11     5

или подходы к смешиванию:

as_tibble(keep(unstack(df,v1 ~ f1), ~length(.x) == 2))
0 голосов
/ 14 декабря 2018

split здесь может быть полезно разделить df$v1 на части, соответствующие df$f1.Поскольку вы всегда извлекаете куски одинаковой длины, их можно просто объединить обратно в data.frame:

spl <- split(df$v1, df$f1)
data.frame(spl[lengths(spl)==2])

#   a b
#1 10 4
#2 11 5

или сделать все это за один вызов, объединив это с Filter:

data.frame(Filter(function(x) length(x)==2, split(df$v1, df$f1)))
#   a b
#1 10 4
#2 11 5
0 голосов
/ 14 декабря 2018

Я хотел бы написать это, может быть, это поможет вам

library(reshape2)

library(dplyr)

aa = data.frame(v1=c('a','a','b','b','c','c','c'),f1=c(10,11,4,5,0,1,2))

cc = aa %>% group_by(v1) %>% summarise(id = length((v1))) 

dd= merge(aa,cc) #get the level 

ee = dd[dd$aa==2,] #select number of level equal to 2

ee$id = rep(c(1,2),nrow(ee)/2) # reset index like (1,2,1,2)

dcast(ee, id~v1,value.var = 'f1')

все готово!

0 голосов
/ 14 декабря 2018

Использование всех базовых функций (но вы должны использовать Tidyverse)

# Add count of instances
x$len <- ave(x$v1, x$f1, FUN = length)

# Filter, drop the count
x <- x[x$len==2, c('f1','v1')]

# Hacky pivot
result <- data.frame(
lapply(unique(x$f1), FUN = function(y) x$v1[x$f1==y])
)
colnames(result) <- unique(x$f1)

> result
   a b
1 10 4
2 11 5
0 голосов
/ 14 декабря 2018

Я мог бы упустить что-то простое здесь, но следующий подход с использованием dplyr работает.

library(dplyr)
nlevels = 2

df1 <- df %>%
        add_count(f1) %>%
        filter(n == nlevels) %>%
        select(-n) %>%
        mutate(rn = row_number()) %>%
        spread(f1, v1) %>%
        select(-rn)

Это дает

#      a     b
#   <int> <int>
#1    10    NA
#2    11    NA
#3    NA     4
#4    NA     5

Теперь, если вы хотите удалить NA мы можем сделать

do.call("cbind.data.frame", lapply(df1, function(x) x[!is.na(x)]))

#   a b
#1 10 4
#2 11 5

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...