Как объединить несколько похожих файлов .csv в один фрейм данных с заданной структурой

У меня есть много файлов .csv, которые похожи по структуре:

1.csv

Type n
A   1
B   20
C   34
D   5
...

2.csv

Type n
A   2
B   15
C   16
D   5
...

Я хочу объединить их во что-то вроде:

Type  n1   n2
  A   1    2
  B   20   15
  C   34   16
  D   5    5
  ...

Когда я использую lapply, я получаю

 Type n  Type   n
  A   1    A    2
  B   20   B    15
  C   34   C    16
  D   5    D    5
  ...

Есть ли какой-нибудь простой способ правильно их комбинировать?

Я открыт для решений в R или Python


person Alice V.    schedule 08.10.2013    source источник
comment
Они похожи по структуре или идентичны по структуре. Если похоже, может понадобиться merge или match. Если идентично, простой cbind должен помочь (в R). Удалите первый столбец из всех файлов, кроме первого, при cbinding и используйте make.names или paste, чтобы получить уникальные имена для n столбцов.   -  person A5C1D2H2I1M1N2O1R2T1    schedule 08.10.2013
comment
Предположительно, вам нужно что-то вроде merge, возможно, в сочетании с do.call.   -  person Ari B. Friedman    schedule 08.10.2013


Ответы (3)


Интерпретация 1: Идентичная структура данных для каждого CSV

Вот два варианта, которые следует рассмотреть, если структура идентична, но сначала несколько примеров данных:

cat("Type n", "A  1", "B  20", "C  34", "D  5", sep = "\n", file = "myfile1.txt")
cat("Type n", "A  2", "B  15", "C  16", "D  5", sep = "\n", file = "myfile2.txt")

Вариант 1. Отбросьте первый столбец при чтении данных, используя "NULL" (с кавычками) в качестве colClasses для столбца, который необходимо удалить. Используйте cbind, чтобы собрать файлы вместе.

x <- read.table("myfile1.txt", header=TRUE)
y <- read.table("myfile2.txt", header=TRUE, colClasses=c("NULL", "numeric"))
cbind(x, y)
#   Type  n  n
# 1    A  1  2
# 2    B 20 15
# 3    C 34 16
# 4    D  5  5

## For more files:
## do.call(cbind, list(x, y, ...))

Вариант 2: прочитать файлы в обычном режиме, затем подмножить с помощью вектора c(FALSE, TRUE), поместить все в list и cbind вместе с первым столбцом любого из объектов.

x1 <- read.table("myfile1.txt", header = TRUE)
y1 <- read.table("myfile2.txt", header = TRUE)

fileList <- list(x1, y1)
cbind(x1[1], do.call(cbind, fileList)[c(FALSE, TRUE)])
#   Type  n n.1
# 1    A  1   2
# 2    B 20  15
# 3    C 34  16
# 4    D  5   5

Конечно, приведенное выше — это лишь минимальные примеры. Я предполагаю, что у вас на самом деле более 2 столбцов в каждом файле. Используйте вектор TRUEs и FALSEs, которые фактически соответствуют вашим столбцам, чтобы сохранить и удалить (соответственно) для второго варианта, и "NULL" и классы объектов для первого варианта.


Интерпретация 2: одинаковая структура данных для каждого CSV

Если структуры данных похожи, но не идентичны, вам может понадобиться использовать вместо них merge. Рассмотрим следующие примеры данных. Первые три файла имеют одинаковую структуру, но четвертый, "myfile4.txt", имеет A, B, D и E в качестве значений «Тип», а остальные три имеют «A», «B», «C» и « Д"

cat("Type n", "A  1", "B  20", "C  34", "D  5", sep = "\n", file = "myfile1.txt")
cat("Type n", "A  2", "B  15", "C  16", "D  5", sep = "\n", file = "myfile2.txt")
cat("Type n", "A  1", "B   5", "C   6", "D  7", sep = "\n", file = "myfile3.txt")
cat("Type n", "A  8", "B   9", "D  11", "E  0", sep = "\n", file = "myfile4.txt")

Вот как мы можем справиться с этим.

  1. Массовое чтение в файлах:

    x <- list.files(pattern="myfile")
    y <- lapply(x, read.table, header = TRUE)
    
  2. Несколько merge, вероятно, приведут к ошибке, если они не могут создавать уникальные имена. Помогите merge, создав уникальные имена для начальных столбцов без идентификаторов.

    library(data.table) ## for `setnames`
    ## setnames will silently assign new names 
    ##   to the original data in list "y"
    invisible(lapply(seq_along(y), function(z) 
      setnames(y[[z]], "n", paste("n", z, sep = "_"))))
    
  3. Используйте Reduce для merge элементов списка вместе, используя столбец «Тип» в качестве «идентификатора».

    Reduce(function(x, y) merge(x, y, by = "Type", all = TRUE), y)
    #   Type n_1 n_2 n_3 n_4
    # 1    A   1   2   1   8
    # 2    B  20  15   5   9
    # 3    C  34  16   6  NA
    # 4    D   5   5   7  11
    # 5    E  NA  NA  NA   0
    
person A5C1D2H2I1M1N2O1R2T1    schedule 08.10.2013
comment
merge даже не упоминается? Бедный merge. Это не вина, что он не так эффективен, как cbind. Он отлично справляется со своей задачей. - person Ricardo Saporta; 08.10.2013
comment
И я только что увидел ваш комментарий выше. Может быть, стоит включить в свой ответ для будущих поисков? - person Ricardo Saporta; 08.10.2013
comment
@RicardoSaporta, слияние включено. - person A5C1D2H2I1M1N2O1R2T1; 08.10.2013
comment
Я чувствую, что в мире R / SO много голосов против по малой причине / без причины. - person Ricardo Saporta; 09.10.2013

в Python вы должны использовать pandas для выполнения следующих операций:

import pandas as pd

df1 = pd.read_csv('1.csv', sep='\s+', index_col=0)
df2 = pd.read_csv('2.csv', sep='\s+', index_col=0)

pd.concat([df1, df2], axis=1)
Out[16]: 
       n   n
Type        
A      1   2
B     20  15
C     34  16
D      5   5

Если вы ожидаете более автоматического переименования столбцов:

pd.merge(df1, df2, left_index=True, right_index=True, suffixes=['1', '2'])
Out[20]: 
      n1  n2
Type        
A      1   2
B     20  15
C     34  16
D      5   5
person Zeugma    schedule 08.10.2013

Другое решение здесь предполагает, что слияние не требуется. Например, если у вас есть три файла, вы можете прочитать их следующим образом:

n <- 1:3
x <- lapply(sprintf('%s.csv', n), read.csv)

Вы просто хотите удалить первый столбец в каждой таблице, поэтому вы можете использовать sapply() на [[.data.frame, чтобы удалить ненужный столбец, а затем объединить все это в один фрейм данных.

data.frame(Type = x[[1]]$Type, sapply(x, '[[', -1))

Или, если вам действительно нужны имена в форме n1, n2 и т. д.:

data.frame(
  Type = x[[1]]$Type, 
  setNames(lapply(x, '[[', -1), paste0('n', n))
)
person Ciarán Tobin    schedule 08.10.2013