научные измерения +- ошибка в таблицах Rmarkdown/bookdown

Что было бы лучшим способом получить хорошую таблицу (например, с kable), если я хочу иметь измерение и его ошибку в форме y +- error или y(error), имея обычные правила для ошибок: иметь 1 значащую цифру в ошибке, такое же количество цифр в значении и так далее. Например:

  • 1.124 \pm 0.003
  • 0.30 \pm 0.02

и так далее.

Воспроизводимый пример

df<-data.frame(
  x=runif(5),
  Delta.x=runif(5)/10,
  y=runif(5),
  Delta.y=runif(5)/7
)
df.print<-with(df, data.frame(
  x=paste0(x, "(", Delta.x, ")"),
  y=paste0(y, "(", Delta.y, ")")
))

kable(df.print)

Если я использую format(x, digits=3) x, y и их дельты, я получаю разные «ширины», и я хотел бы получить одинаковое количество цифр после запятой.


person Javi_VM    schedule 12.03.2018    source источник
comment
Вы можете использовать sprintf: df.print<-with(df, data.frame( x=paste(sprintf("%.2f", x), "±", sprintf("%.2f", Delta.x)), y=paste(sprintf("%.2f", y), "±", sprintf("%.2f", Delta.y)) ))   -  person JasonAizkalns    schedule 12.03.2018
comment
Есть ли способ выбрать количество цифр ("%.2f", "%.3f") автоматически на основе значений Delta.x или Delta.y?   -  person Javi_VM    schedule 12.03.2018
comment
См. это сообщение.   -  person JasonAizkalns    schedule 12.03.2018


Ответы (1)


Вот tidyverse подход к вашей проблеме, возможно, очень подробный. Некоторые пояснения:

1) Первый блок mutate() округляет оба столбца Delta до одной значащей цифры и преобразует ее в символ; это сохраняет длину.

2) Второй блок mutate() округляет «обычные» столбцы x и y, чтобы они имели ту же длину, что и столбцы Delta. - 2L позволяет избежать ложного округления на основе числа перед . и самого . в столбцах Delta.

3) Третий блок mutate() сначала обрабатывает две "необычные" ситуации: первый блок if_else() обрабатывает ситуации, когда округленное число y не имеет . и цифр, а значение Delta.y имеет. Второй if_else() заботится о ситуациях, когда последней цифрой в процессе округления является 0, которая R отбрасывается при округлении. Обе меры повторяются для столбца x.

4) Четвертый блок mutate() добавляет пробелы в конце значений в столбцах x и y, чтобы убедиться, что номера ошибок выровнены.

5) Команды unite() и mutate() в конце объединяют столбцы и добавляют скобки для второго числа.

library("tidyverse")
library("knitr")

df %>% 
  mutate(Delta.x = signif(Delta.x, digits = 1L), 
         Delta.x = as.character(Delta.x), 
         Delta.y = signif(Delta.y, digits = 1L), 
         Delta.y = as.character(Delta.y)) %>% 
  mutate(x = round(x, digits = str_count(Delta.x) - 2L), 
         x = as.character(x),
         y = round(y, digits = str_count(Delta.y) - 2L), 
         y = as.character(y)) %>% 
  mutate(y = if_else(condition = str_count(y, "\\.") == 0, 
                     true = str_c(y, str_dup("0", str_count(Delta.y) - str_count(y) - 1L), sep = "."),
                     false = y),
         y = if_else(condition = str_count(Delta.y) - str_count(y) != 0,
                     true = str_c(y, str_dup("0", times = str_count(Delta.y) - str_count(y))),
                     false = y),
         x = if_else(condition = str_count(x, "\\.") == 0, 
                     true = str_c(x, str_dup("0", str_count(Delta.x) - str_count(x) - 1L), sep = "."),
                     false = x),
         x = if_else(condition = str_count(Delta.x) - str_count(x) != 0,
                     true = str_c(x, str_dup("0", times = str_count(Delta.x) - str_count(x))),
                     false = x)) %>% 
  mutate(x = if_else(condition = str_count(x) < max(str_count(x)),
                     true = str_c(x, str_dup(" ", times = max(str_count(x)) - str_count(x))),
                     false = x),
         y = if_else(condition = str_count(y) < max(str_count(y)),
                     true = str_c(y, str_dup(" ", times = max(str_count(y)) - str_count(y))),
                     false = y)) %>%
  unite(x, x, Delta.x, sep = " (") %>% 
  unite(y, y, Delta.y, sep = " (") %>% 
  mutate(x = str_c(x, ")"), 
         y = str_c(y, ")")) %>% 
  kable()


|x           |y             |
|:-----------|:-------------|
|1.0  (0.1)  |0.20  (0.01)  |
|0.12 (0.07) |0.8   (0.1)   |
|0.71 (0.03) |0.18  (0.09)  |
|0.63 (0.02) |0.805 (0.003) |
|0.27 (0.09) |0.106 (0.008) |

Кроме того, вы можете установить глобальное options(scipen = 999) (или любое другое большое число), чтобы избежать научного представления чисел, например. 2e-5 (что в случае вашего kable должно выглядеть как 0.00002).

EDIT: обновлены и уточнены некоторые команды.

ОБНОВЛЕНИЕ (Javi_VM)

Я просто превратил его в функцию. Вы можете указать либо 2 вектора, либо 1 data.frame с двумя столбцами. Он по-прежнему не поддерживает экспоненциальное представление (например, 1,05 10 ^ 9), но для начала все в порядке.

scinumber <- function(df=NULL, x, Delta.x){
  if (is.null(df)) {
    df <- data.frame(
      x = x,
      Delta.x = Delta.x
    )
  } else {
    colnames(df)[colnames(df)==x] <- "x"
    colnames(df)[colnames(df)==Delta.x] <- "Delta.x"
  }
  require(tidyverse)
  options(scipen = 999)
  output <- 
    df %>% 
    mutate(Delta.x = signif(Delta.x, digits = 1L), 
           Delta.x = as.character(Delta.x)) %>% 
    mutate(x = round(x, digits = str_count(Delta.x) - 2L), 
           x = as.character(x)
    ) %>% 
    mutate(x = if_else(condition = str_count(x, "\\.") == 0, 
                       true = str_c(x, str_dup("0", str_count(Delta.x) - str_count(x) - 1L), sep = "."),
                       false = x),
           x = if_else(condition = str_count(Delta.x) - str_count(x) != 0,
                       true = str_c(x, str_dup("0", times = str_count(Delta.x) - str_count(x))),
                       false = x)) %>% 
    mutate(x = if_else(condition = str_count(x) < max(str_count(x)),
                       true = str_c(x, str_dup(" ", times = max(str_count(x)) - str_count(x))),
                       false = x)) %>%
    unite(x, x, Delta.x, sep = " (") %>% 
    mutate(x = str_c(x, ")"))

  return(output)
}
person Supertasty    schedule 12.03.2018
comment
Спасибо. Однако ваш ответ имеет две проблемы. Во-первых, я этого не понимаю (думаю, мне стоит взглянуть на tidiverse). Во-вторых, у меня все еще есть проблема с автоматическим получением количества цифр, так что неопределенность всегда имеет только одну значащую цифру. - person Javi_VM; 12.03.2018
comment
Извините, я неправильно понял ваш вопрос изначально; Я соответствующим образом обновил свой ответ, который теперь должен динамически давать желаемый результат. Дайте мне знать, если это то, что вы искали! - person Supertasty; 13.03.2018
comment
Большое спасибо за ваше редактирование, @Supertasty. Остается одно: преобразовать это в функцию, чтобы было проще пользоваться, но я не буду просить вас об этом, я попытаюсь сделать это сам. Еще раз спасибо!! Я сделаю дополнительные тесты, чтобы убедиться, что это работает во всех случаях... - person Javi_VM; 14.03.2018