Как суммировать несколько CSV-файлов («ячейки» данных с сеткой со 145 строками и 140 столбцами), чтобы получить CSV-файл с таким же размером - PullRequest
0 голосов
/ 03 июня 2019

У меня есть несколько csv-файлов, которые я извлек из (формат NetCDF). Это загруженные онлайн данные (ячейки данных с ежемесячными осадками с 145 строками и 139 столбцами) мне нужно суммировать эти ежемесячные CSV-файлы за каждый год (за период 60 лет), чтобы получить среднее значение между 60 суммами.

[Вот и мы! ответ, который у меня был (не самый умный, но тот, с которым я работал) PS: если у вас много данных, вы можете создать фрейм данных с датами и статистическими данными, которые будут выполняться очень быстро!

1 - в качестве первого шага я организовал все свои данные, создав «репертуар» для каждого года с полем «данные», это долгий путь, но он работает! ,

2 - затем я создаю фрейм данных для каждого месяца, здесь для первого месяца 1940 года

 df1<-read.csv2(file= "./1940-01-01.csv", sep="," , dec="." )
 df2<-read.csv2(file=   "./1940-02-01.csv", sep="," , dec="." ) 
    ...
 df12<- read.csv2(file=   "./1940-12-01.csv", sep="," , dec="." )

Ваши фреймы данных будут видны в глобальной среде

3 - Я СУММАЮ все свои кадры данных (ячейка за ячейкой), чтобы в результате получить один кадр данных с 145 (ROWS) и (141 КОЛОННАМИ) [одинаковое измерение]

за 1940 год

 df_1940_sum <-df1+df2+df3+df4+df5+df6+df7+df8+df9+df10+df11+df12 

4 - Я сделал результат как вывод (файл CSV) в моем репертуаре

write.table(df_sum, file="df_1940.csv", sep= ",")

1 Ответ

1 голос
/ 04 июня 2019

Три возможных решения, в зависимости от ваших строгих потребностей.

Начиная с вашего df, давайте создадим список из трех. Поскольку в столбце есть так много столбцов, я сосредоточусь лишь на нескольких, но для всех остальных столбцов выполняются вычисления.

dflst <- list(df, df, df)
df[, c("X", "V1", "V20", "V21", "V34")]
#   X V1   V20   V21   V34
# 1 1 NA 63.06 36.64 11.69
# 2 2 NA 38.49 31.73    NA

TL, DR: Я думаю, что " Случай 3 ", вероятно, является лучшим (наиболее гибким, наиболее надежным) из трех, учитывая некоторые предположения, и в этом случае вы можете пропустить это «кондиционирование имени столбца» и случаи 1-2, и пропустите прямо ко дну.


Предварительная обработка: Подготовка кадра

Предположение для некоторых из этих случаев состоит в том, что все кадры имеют одинаковые размеры и все столбцы находятся в одном и том же порядке. Если это всегда так, то вы можете пропустить этот шаг «подготовки».

Однако, если это не безопасное предположение, можно в некотором смысле «обусловить» их. Я продемонстрирую со списком из трех поддельных кадров, все немного по-другому:

somelst <- list(data.frame(x=1,y=2), data.frame(y=3, x=4), data.frame(x=5, z=6))
some_names <- names(somelst[[1]])
somelst <- lapply(somelst, `[`, some_names)
# Error in `[.data.frame`(X[[i]], ...) : undefined columns selected

Чтобы исправить это, нам нужно использовать только общие имена. Обратите внимание, что если это произойдет, то следующие шаги будут молча отбрасывать нестандартные столбцы.

somelst <- lapply(somelst, function(l) l[, intersect(some_names, names(l)), drop=FALSE])
somelst
# [[1]]
#   x y
# 1 1 2
# [[2]]
#   x y
# 1 4 3
# [[3]]
#   x
# 1 5

Порядок столбцов теперь стандартный, но (относится к случаям 1-2 ниже) у нас пропущены столбцы. Исправлено:

somelst <- lapply(somelst, function(l) { l[, setdiff(some_names, names(l))] <- NA; l; })
somelst
# [[1]]
#   x y
# 1 1 2
# [[2]]
#   x y
# 1 4 3
# [[3]]
#   x  y
# 1 5 NA

(Этот последний шаг просто добавляет все- NA значения для пропущенных столбцов.)

Итак, я применю это к нашим данным (хотя мы знаем, что здесь нет операции, поскольку все элементы списка являются идентичными кадрами):

df_names <- names(dflst[[1]])
dflst <- lapply(dflst, function(l) l[, intersect(df_names, names(l)), drop=FALSE])
dflst <- lapply(dflst, function(l) { l[, setdiff(df_names, names(l))] <- NA; l; })

Случай 1: X - это данные

Я думаю, что это маловероятно, но я включил его для полноты на тот случай, если самое простое - это то, что ожидается:

out <- Reduce(`+`, dflst)
out[, c("X", "V1", "V20", "V21", "V34")]
#   X V1    V20    V21   V34
# 1 3 NA 189.18 109.92 35.07
# 2 6 NA 115.47  95.19    NA

Случай 2: X является ключом

В этом случае мы просто складываем все вместе, но без изменения идентификатора X.

Примечание : предполагается, что все идентификаторы присутствуют во всех кадрах и в том же порядке .

out <- df # really just need "X" and the right number of columns
          # ... none of the other values are used
out[,-1] <- Reduce(`+`, lapply(dflst, `[`, -1))
out[, c("X", "V1", "V20", "V21", "V34")]
#   X V1    V20    V21   V34
# 1 1 NA 189.18 109.92 35.07
# 2 2 NA 115.47  95.19    NA

Можно проверить это предположение примерно так:

identical(df$X, Reduce(function(a, b) if (identical(a,b)) a else FALSE, lapply(dflst, `[[`, "X")))
# [1] TRUE

Любая разница будет указывать на причину более (не очень простого) кондиционирования или Случай 3 (что по-прежнему является моей общей рекомендацией).


Случай 3: переменные (но все же важные) имена столбцов

В этом случае нам , а не нужно предварительно подготовить данные, как мы это делали, для нормализации имен столбцов и их порядка, как это делается естественным образом. Предполагается, что имена столбцов являются важными и стандартными. Это означает, что если вы видите "V22" в одном кадре, это означает "V22" во всех кадрах, и что ничто другое не совпадает с "V22".

Однако не предполагает, что все имена в одном кадре будут в другом, поэтому отсутствие столбца обрабатывается плавно. Если все они находятся там и в одном и том же порядке (как и следовало ожидать от автоматизированного набора данных), это тоже работает.

Это может быть сделано в base-R и data.table, но я считаю, что грамотная форма dplyr (и семья) является наиболее ясной для демонстрации:

library(dplyr)
library(purrr)
library(tidyr)

out <- map(dflst, ~ gather(., k, v, -X)) %>%
  bind_rows(.) %>%
  group_by(X, k) %>%
  summarize(v = if (all(is.na(v))) NA_real_ else sum(v, na.rm = TRUE)) %>%
  spread(k, v)
out[, c("X", "V1", "V20", "V21", "V34")]
# # A tibble: 2 x 5
# # Groups:   X [2]
#       X    V1   V20   V21   V34
#   <int> <dbl> <dbl> <dbl> <dbl>
# 1     1    NA  189. 110.   35.1
# 2     2    NA  115.  95.2  NA  

(Это tibble, чье представление на консоли имеет некоторые заметные отличия от необработанных фреймов. Примечательно, что значения "V20" выглядят иначе, хотя в этом случае это всего лишь хороший способ сохранить tibble «аккуратные» вещи со значительными цифрами и т. д. Если вместо этого вы наберете as.data.frame(out[, c("X", "V1", "V20", "V21", "V34")]), вы увидите, что результаты одинаковы.)

Пояснение:

  • map(dflst, ...) делает что-то для каждого кадра в списке;
  • gather(., k, v, -X) преобразует из «широкого» в «длинный» формат, где отдельный кадр будет выглядеть так:

    gather(df, k, v, -X) %>% head(.)
    #   X  k  v
    # 1 1 V1 NA
    # 2 2 V1 NA
    # 3 1 V2 NA
    # 4 2 V2 NA
    # 5 1 V3 NA
    # 6 2 V3 NA
    
  • bind_rows(.) объединяет список кадров в один сцепленный со строкой кадр

  • group_by(X, k) %>% summarize(...) выполняет агрегацию по id и по (исходному) столбцу, поэтому все X==1 и k=="V1" объединяются в одну строку и т. Д.
  • if (all(is.na(v))) NA_real_ else sum(v, na.rm = TRUE) немного взломан;обычно я делал бы просто sum(v, na.rm = TRUE) (без if), но в других случаях поле all- NA сохранялось как NA, где этот sum преобразует его в 0.Я подумал, что важно сохранить идею о том, что «в этом поле никогда не было данных», поэтому, если все они равны NA, оставьте его NA, в противном случае дайте сумму всех не NA полей.
  • spread(k, v) преобразует обратно из «длинного» в «широкий» формат.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...