На днях в официальном блоге RStudio проф. Хэдли Уикхэм объявил о выходе своего нового пакета - tidyr, функции которого предназначены для подготовки "опрятных" (англ. tidy) данных. Ниже приведен перевод этого объявления.
"Опрятные" данные - это данные, с которыми легко работать: их легко преобразовать (например. примощи dplyr), визуализировать (при помощи ggplot2 или ggvis) и использовать для построения модели (при помощи сотен R-пакетов). Два наиболее важных свойства таких данных состоят в следующем:
- Каждый столбец в таблице соответствует одной переменной;
- Каждая строка соответствует одному наблюдению.
Приведение данных к такому формату значительно облегчает работу, поскольку он обеспечивает единообразный подход для обращения к переменным (по именам столбцов) и наблюдениям (по номерам строк). Используя "опрятные" данные и соответствующие программные инструменты, вы тратите меньше времени на то, чтобы решить, как подать результаты вычислений одной функции на другую функцию, и в результате у вас появляется больше времени для изучения свойств данных.
Для преобразования плохо упорядоченных данных вы сначала определяете интересующие вас переменные, а затем используете средства tidyr, чтобы сделать из этих переменных самостоятельные столбцы. Пакет tidyr содержит три основные функции для преобразования плохо организованных данных: gather() ("собирать"), separate() ("разделять") и spread() ("распределять").
Функция gather() принимает несколько столбцов и преобразует их в пары "ключ - значение", в результате чего "широкие" таблицы данных превращаются в "длинные". Идентичные по действию функции имеются также в других пакетах: melt() (из пакета reshape2), pivot() (spreadsheets) и fold() (databases). Вот пример использования gather() на вымышленном наборе данных. В этом гипотетическом экперименте мы дали испытуемым два разных лекарственных препарата и затем измерили у них частоту сердечных сокращений:
Таким образом, у нас есть три переменные (имя испытуемого, название препарата и частота сокращений), однако в приведенной выше таблице messy только переменная "имя пациента" (name) представлена в виде отдельного столбца. Применим функцию gather() для преобразования столбцов a и b в пары "ключ - значение" (т.е. "препарат (drug) - частота сокращений (heartrate)"):
Иногда две переменные бывают представлены в виде одного столбца. Функция separate() позволяет разделить их (см. также ?extract - эта функция выполняет разделение, используя регулярные выражения). Рассмотрим (вымышленный) пример, приведенный ранее на сайте Stackoverflow. Имеются измерения длительности разговоров по мобильному телефону, сделанных испытуемыми в двух местах - дома и на работе, в два разных периода времени. Формирование этих четырех групп испытуемых было выполнено случайным образом.
Для преобразования этих плохо упорядоченных данных мы сначала применим gather(), чтобы превратить столбцы work.T1, home.T1, work.T2 и home.T2 в соответствующие пары "значение - ключ" (для экономии места ниже приведены только первые 8 строк итоговой таблицы):
Дальше мы применим функцию separate(), чтобы разделить key на местоположение (location) и период времени (Time), используя регулярное выражение, которое соответствует знаку-разделителю соответствующих значений (т.е. точке):
Последний инструмент - функция spread() - принимает два столбца (пара "ключ - значение") и "разносит" их по разным столбцам, превращая "длинную" таблицу в "широкую". В других пакетах имеются аналогичные функции: cast() (reshape2), unpivot() (spreadsheets) и unfold() (databases). Функция spread() используется в случаях, когда переменные образуют строки вместо столбцов. Эта функция будет применяться реже, чем gather() или separate() и поэтому для получения дополнительной информации следует обратиться к справочной документации и приведенным там примерам.
Точно так же, как пакет reshape2 обладал меньшей функциональностью по сравнению с reshape, пакет tidyr предоставляет меньше возможностей, чем reshape2. Он предназначен исключетельно для подготовки "опрятных" данных, а не для переформатирования таблиц в целом. В частности, имеющиеся функции работают только с таблицами данных и не позволяют аггрегировать данные (например, по средним значениям). Это упрощает функции tidyr: каждая из них делает только одно дело, но делает его хорошо. Для более сложных операций следует объединять возможности tidyr и dplyr, используя оператор %>%.
Дополнительую информацию по концепции "опрятных данных" можно найти в соответствующей статье Хэдли Уикхэма. См. также руководство, доступное по команде vignette("tidy-data"), и примеры, доступные по команде demo(package = "tidyr"). Кроме того, обратите внимание на отличные ответы по этой теме на сайте Stackoverflow.
messy %>% gather(drug, heartrate, a:b) name drug heartrate 1 Wilbur a 67 2 Petunia a 80 3 Gregory a 64 4 Wilbur b 56 5 Petunia b 90 6 Gregory b 50
Иногда две переменные бывают представлены в виде одного столбца. Функция separate() позволяет разделить их (см. также ?extract - эта функция выполняет разделение, используя регулярные выражения). Рассмотрим (вымышленный) пример, приведенный ранее на сайте Stackoverflow. Имеются измерения длительности разговоров по мобильному телефону, сделанных испытуемыми в двух местах - дома и на работе, в два разных периода времени. Формирование этих четырех групп испытуемых было выполнено случайным образом.
Для преобразования этих плохо упорядоченных данных мы сначала применим gather(), чтобы превратить столбцы work.T1, home.T1, work.T2 и home.T2 в соответствующие пары "значение - ключ" (для экономии места ниже приведены только первые 8 строк итоговой таблицы):
tidier <- messy %>% gather(key, time, -id, -trt) tidier %>% head(8) id trt key time 1 1 treatment work.T1 0.08513597 2 2 control work.T1 0.22543662 3 3 treatment work.T1 0.27453052 4 4 control work.T1 0.27230507 5 1 treatment home.T1 0.61582931 6 2 control home.T1 0.42967153 7 3 treatment home.T1 0.65165567 8 4 control home.T1 0.56773775
Дальше мы применим функцию separate(), чтобы разделить key на местоположение (location) и период времени (Time), используя регулярное выражение, которое соответствует знаку-разделителю соответствующих значений (т.е. точке):
tidy <- tidier %>% separate(key, into = c("location", "Time"), sep = "\\.") tidy %>% head(8) id trt location Time time 1 1 treatment work T1 0.08513597 2 2 control work T1 0.22543662 3 3 treatment work T1 0.27453052 4 4 control work T1 0.27230507 5 1 treatment home T1 0.61582931 6 2 control home T1 0.42967153 7 3 treatment home T1 0.65165567 8 4 control home T1 0.56773775
Последний инструмент - функция spread() - принимает два столбца (пара "ключ - значение") и "разносит" их по разным столбцам, превращая "длинную" таблицу в "широкую". В других пакетах имеются аналогичные функции: cast() (reshape2), unpivot() (spreadsheets) и unfold() (databases). Функция spread() используется в случаях, когда переменные образуют строки вместо столбцов. Эта функция будет применяться реже, чем gather() или separate() и поэтому для получения дополнительной информации следует обратиться к справочной документации и приведенным там примерам.
Точно так же, как пакет reshape2 обладал меньшей функциональностью по сравнению с reshape, пакет tidyr предоставляет меньше возможностей, чем reshape2. Он предназначен исключетельно для подготовки "опрятных" данных, а не для переформатирования таблиц в целом. В частности, имеющиеся функции работают только с таблицами данных и не позволяют аггрегировать данные (например, по средним значениям). Это упрощает функции tidyr: каждая из них делает только одно дело, но делает его хорошо. Для более сложных операций следует объединять возможности tidyr и dplyr, используя оператор %>%.
Дополнительую информацию по концепции "опрятных данных" можно найти в соответствующей статье Хэдли Уикхэма. См. также руководство, доступное по команде vignette("tidy-data"), и примеры, доступные по команде demo(package = "tidyr"). Кроме того, обратите внимание на отличные ответы по этой теме на сайте Stackoverflow.
Отправить комментарий