Как да комбинирате няколко подобни .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. Няколко merges вероятно ще доведат до грешка, ако не могат да създават уникални имена. Помогнете на 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 елементите от списъка заедно, като използвате колоната „Тип“ като „id“.

    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