R — Подсчет наблюдений (строк) в столбце и вычисление в процентах от общего числа наблюдений

#r #count #percentage

Вопрос:

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

 ID   Item     Class  Value  Date
1    Eggs     A      5      07/07/21
2    Eggs     A      4.5    07/07/21
3    Cereal   C      2      07/07/21
4    Eggs     B      3.5    07/07/21
5    Bread    B      2.5    07/07/21
6    Juice    A      3      07/07/21
7    Juice    C      1.5    07/07/21
8    Eggs     C      2      07/07/21
9    Bread    A      3      07/07/21
10   Juice    A      3      07/07/21
 

Это всего лишь пример, фактические данные содержат около 8 тыс. строк (и более 300 кадров данных). Я хочу создать новый df, который

  1. вычисляет процент наблюдений в Item столбце (например, в столбце 10 элементов , четыре из которых являются Eggs , таким образом, процент Eggs равен 40)
  2. вычисляет среднее Value значение по каждой Item группе

В идеале окончательные данные должны выглядеть примерно так:

 Item    Percentage  Average_Value  Date
Eggs    40          3.75           07/07/21
Cereal  10          2              07/07/21
Bread   20          2.75           07/07/21
Juice   30          2.5            07/07/21
 

Несколько вещей, которые следует отметить — я хочу сделать это для более чем 300 различных csv (где хранятся мои данные) и создать единый файл df с этой новой информацией. Каждый csv ссылается на другую дату, поэтому окончательный df будет выглядеть примерно так, как указано выше, только с еще четырьмя строками, но с другими значениями и другой датой. Я знаю, что для этого мне нужно будет использовать цикл for, и, возможно, мне следует разобраться с этой частью позже, но подумал, что об этом стоит упомянуть сейчас. Наконец, в какой-то момент я, возможно, захочу также рассчитать среднее значение Class . Было бы мне лучше сделать для этого отдельный df, поскольку я не вижу, как еще я мог бы это сделать?

Ответ №1:

Выполните эти шаги в tidyverse

  • установите рабочий каталог в каталог, в котором хранятся более 300 csv-файлов
  • считайте все 300 csv-имен в temp
  • предполагая, что каждое имя csv относится к вашему date имени, вам нужно немного изменить код
  • используя map и imap_dfr , как описано ниже, вы можете выполнить один и тот же код для каждого файла только один раз, и в результате у вас будет один кадр данных
 setwd('my/path/here')

temp <- list.files(pattern = '*.csv')

library(tidyverse)

map(temp, read.csv) %>% setNames(gsub('.csv', '', temp)) %>%
  imap_dfr(~ .x %>% group_by(item) %>%
         summarise(Percentage = n()/nrow(df)*100, 
                   Average_Value = mean(Value), .groups = 'drop') %>%
         mutate(Date = .y))
 

Если вместо этого все ваши резюме содержат столбец даты, сделайте это

 map_dfr(temp, ~read.csv(.x) %>% group_by(item, date) %>%
          summarise(Percentage = n()/nrow(df)*100, 
                    Average_Value = mean(Value), .groups = 'drop'))
 

Комментарии:

1. Большое спасибо @AnilGoyal. Работает отлично. У вас есть какие-либо идеи о том, как бы я также добавил столбец с количеством элементов (а также в процентах)?

2. @Шутки, да! не могли бы вы показать мне несколько строк, как выглядит один из ваших файлов? и как это называется?

3. Было бы лучше продолжить это в приватном чате? У меня здесь ограниченное количество символов, чтобы записать примерные данные! 🙂

4. @Japes, ты можешь написать мне по электронной почте

Ответ №2:

Работает ли это:

 library(dplyr)
df %>% group_by(Item) %>% summarise(Percentage = n()/nrow(df)*100, Average_Value = mean(Value))
# A tibble: 4 x 3
  Item   Percentage Average_Value
  <chr>       <dbl>         <dbl>
1 Bread          20          2.75
2 Cereal         10          2   
3 Eggs           40          3.75
4 Juice          30          2.5 
 

Комментарии:

1. Это отлично работает, спасибо! Единственное, что мне еще нужно сделать, это добавить столбец даты. Есть какие-нибудь мысли о том, как это сделать? Я уверен, что это, вероятно, очень просто, но программирование-не моя сильная сторона!

2. @Japes, если вам тоже нужна Date колонка, попробуйте: df %>% group_by(Item, Date) %>% summarise(Percentage = n()/nrow(df)*100, Average_Value = mean(Value))

3. Блестяще, работает как заклинание, спасибо! Если бы я мог быть настолько смелым, чтобы спросить еще об одной вещи… Если я также хочу вычислить среднее значение другого столбца, назовем его value2 (опять же, он будет сгруппирован по Item ), как бы я добавил это в эту строку кода? В принципе, могу ли я рассчитать средние значения двух столбцов в одной строке кода?

4. Ложная тревога, выяснил это методом проб и ошибок. Публикуйте здесь, если это полезно для кого-то еще: df %>% group_by(Item, Date) %>% summarise(Percentage = n()/nrow(df)*100, Average_Value = mean(Value),Average_Value2 = mean(Value2))

Ответ №3:

Вы можете merge получить результат proportions из table с формой результата aggregate mean из Value ~ Item . В случае Date , если также необходимо быть там, это может быть добавлено с помощью cbind или data.frame .

 merge(aggregate(cbind(Average_Value = Value) ~ Item, x, mean)
    , proportions(table(x$Item))*100
    , by.y=1, by.x="Item")[c(1,3,2)]
#    Item Freq Average_Value
#1  Bread   20          2.75
#2 Cereal   10          2.00
#3   Eggs   40          3.75
#4  Juice   30          2.50
 

Или использовать только aggregate :

 aggregate(Value ~ Item, x, function(y) c(Freq=length(y)/nrow(x)*100, Average=mean(y)))
#    Item Value.Freq Value.Average
#1  Bread      20.00          2.75
#2 Cereal      10.00          2.00
#3   Eggs      40.00          3.75
#4  Juice      30.00          2.50
 

Комментарии:

1. Эй, спасибо за предложение. В итоге я использовал метод dplyr / summarise / group_by (в основном потому, что он немного короче), но я уверен, что это тоже работает 🙂

Ответ №4:

Перечислите все файлы, которые вы хотите использовать с помощью list.files . Объедините их в один файл с помощью map_df и для каждого Date рассчитайте процент Item присутствующих и его среднее значение.

 library(tidyverse)

filenames <- list.files(pattern = '\.csv



)

map_df(filenames, read_csv) %>%
group_by(Date, Item) %>%
summarise(Percentage = n(),
Average_Value = mean(Value)) %>%
mutate(Percentage = prop.table(Percentage) * 100) %>%
ungroup -> result

result