использование нескольких фреймов данных и таблицы поиска для выполнения функций в r

Я новичок в r и у меня сложный набор данных, поэтому надеюсь, что мое объяснение правильное. У меня есть несколько фреймов данных, которые мне нужно использовать для выполнения ряда действий. Вот один пример. У меня есть три кадра данных. Один из них представляет собой список названий видов и соответствующих кодов:

>df.sp
    Species Code
    Picea   PI
    Pinus   CA

Еще один список сайтов с данными об изобилии видов в разных местах (dir). К сожалению, порядок видов другой.

>df.site
Site  dir total  t01 t02 t03 t04
2         Total   PI  CA  AB  T
2     N    9      1   5   na na
2                 AB  ZI PI CA
2     S    5     2   2  1  4
3                 DD  EE AB YT
3     N    6     1   1  5   3
3                 AB YT  EE  DD
3     S     5     4   3  1   1

Затем у меня также есть фрейм данных признаков, соответствующих видам:

>df.trait
Species  leaft  rootl
Picea     0.01    1.2
Pinus     0.02    3.5

В качестве примера я хочу получить среднее значение для каждого признака (df.trait$leaft и df.trait$rootl) для всех видов на сайт (df.site$Site) и на местоположение сайта (df. сайт$сайт N, S). Таким образом, результат будет для первой строки:

Site dir leaft rootl
2    N   0.015  2.35

Я надеюсь, что в этом есть смысл. Мне очень сложно продумать, как действовать. Я пытался работать с этот пост и это (и многие другие), но потерялись. Спасибо за помощь. Действительно ценится.

ОБНОВЛЕНИЕ: Вот пример фактического df.site (уменьшенный) с использованием dput:

> dput(head(df.site))
structure(list(Site = c(2L, 2L, 2L, 2L, 2L, 2L), dir = c("rep17316", 
"N", "", "S", "", "SE"), total = c("Total", "9", "", 
"10", "", "9"), t01 = c("PI", "4", "CA", "1", "SILLAC", 
"3"), t02 = c("CXBLAN", "3", "ZIZAUR", "4", "OENPIL", "2"), 
    t03 = c("ZIZAPT", "1", "ECHPUR", "2", "ASCSYR", "2")), .Names = c("site", "dir", "total", "t01", "t02", "t03"), row.names = 2:7, class = "data.frame")

person KNN    schedule 12.02.2019    source источник
comment
df.site выглядит очень плохо, поскольку столбцы не имеют согласованного типа (например, столбец total содержит такие слова, как Total, и числа, подобные 9, столбец t04 содержит такие слова, как "T" (если только это не логическое значение TRUE?), строки типа "na", в котором, вероятно, должны отсутствовать значения NA, числа, такие как 4, и обычные строки, такие как "CA". Первым шагом определенно должно быть приведение этих данных в форму. Не могли бы вы поделиться подмножеством этого фрейма данных с dput, чтобы его можно было копировать/вставлять и мы можем видеть все типы столбцов? (Также было бы неплохо поделиться остальными с dput()...)   -  person Gregor Thomas    schedule 12.02.2019
comment
См. отличный FAQ, если вам нужна помощь в создании воспроизводимого примера. dput(droplevels(df.site[1:10, ])) наверное хорошо.   -  person Gregor Thomas    schedule 12.02.2019
comment
Однако лучшим вопросом может быть возвращение к тому, как вы импортировали df.site, и исправление процесса импорта вместо того, чтобы пытаться исправить испорченные данные, которые возникли в результате... не видя образца источника, трудно понять, будет ли это быть меньше работы или нет.   -  person Gregor Thomas    schedule 12.02.2019
comment
Спасибо. Да, df.site — это кошмар, который является частью проблемы. Он был импортирован правильно, просто это сложный файл csv для работы. Я добавил уменьшенную версию, используя dput, как было предложено.   -  person KNN    schedule 12.02.2019
comment
Не имеет отношения к R, но не будет ли ваш пример столбца Species более подходящим названием genus? :)   -  person DanTan    schedule 12.02.2019


Ответы (1)


Вам придется сначала преобразовать ваши данные в гораздо более чистую форму. Я предполагаю, что структура, которую вы dput выше, соответствует всему вашему df.site фрейму данных; а именно, что строки являются парными, первая из которых указывает код вида, вторая из которых имеет счет (или какие-то другие собранные данные?).

Начиная с df в качестве фрейма данных, который вы dput() выше, я сначала смоделирую некоторые данные для двух других фреймов данных:

df.sp <- data.frame(Species = paste0("species",1:8),
                    Code = c("ECHPUR", "CXBLAN", "ZIZAPT",
                             "CAMROT", "SILLAC", "OENPIL",
                             "ASCSYR", "ZIZAUR"))
df.sp
#>    Species   Code
#> 1 species1 ECHPUR
#> 2 species2 CXBLAN
#> 3 species3 ZIZAPT
#> 4 species4 CAMROT
#> 5 species5 SILLAC
#> 6 species6 OENPIL
#> 7 species7 ASCSYR
#> 8 species8 ZIZAUR

df.trait <- data.frame(Species = paste0("species",1:8),
                       leaft = round(runif(8, max=.2), 2),
                       rootl = round(runif(8, min=1, max=4),1))

df.trait
#>    Species leaft rootl
#> 1 species1  0.12   2.5
#> 2 species2  0.04   2.6
#> 3 species3  0.12   2.1
#> 4 species4  0.05   1.1
#> 5 species5  0.15   2.5
#> 6 species6  0.15   3.3
#> 7 species7  0.05   3.9
#> 8 species8  0.13   2.1

Во-первых, давайте очистим df, переместив эти вторые строки, содержащие собранные данные, и переместив эти значения в новый набор столбцов:

library(dplyr)

df.clean <- df %>% 
  #for each row, copy the direction and total from the following row
  mutate_at(vars(matches("dir|total")), lead) %>% 
  #create new columns for observed data and fill in values from following row
  mutate_at(vars(matches("t\\d+$")), 
            .funs = funs(n = lead(.))) %>% 
  #filter to rows with species code in t01
  filter(t01 %in% df.sp$Code) %>% 
  #drop "total" column (doesn't make sense after reshape)
  select(-total)

df.clean
#>   site dir    t01    t02    t03 t01_n t02_n t03_n
#> 1    2   N ECHPUR CXBLAN ZIZAPT     4     3     1
#> 2    2   S CAMROT ZIZAUR ECHPUR     1     4     2
#> 3    2  SE SILLAC OENPIL ASCSYR     3     2     2

Теперь у нас есть два набора соответствующих столбцов, которые имеют коды видов и значения соответственно. Чтобы преобразовать фрейм данных в длинную форму, мы будем использовать melt() из пакета data.table. Другие примеры того, как это сделать, см. в ответах на этот вопрос.

library(data.table)

df.clean <- df.clean %>% 
  setDT() %>% #convert to data.table to use data.tabel::melt
  melt(measure.vars = patterns("t\\d+$", "_n$"),
       value.name = c("Code", "Count") ) %>% 
  #drop "variable" column, which isn't needed
  select(-variable)

Наконец, присоединитесь к своим трем фреймам данных:

#merge tables together
df.summaries <- df.clean %>% 
  left_join(df.sp) %>% 
  left_join(df.trait)

На этом этапе вы должны быть в состоянии обобщить свои данные по интересующим вас группам, используя group_by и summarise.

person DanTan    schedule 12.02.2019
comment
Вот это да. Спасибо, что потратили столько времени, пытаясь мне помочь! Это действительно очень полезно. Я боролся дольше, чем хотел бы признать, пытаясь привести это в пригодный для использования формат. На один огромный шаг ближе к тому, что мне нужно сделать. Спасибо, - person KNN; 13.02.2019