#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, который
- вычисляет процент наблюдений в
Item
столбце (например, в столбце 10 элементов , четыре из которых являютсяEggs
, таким образом, процентEggs
равен 40) - вычисляет среднее
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