2016-06-21 12 views
1

この種のものではRで比較的新しいものがかなり検索され、多くのものが見つかりませんでした。重複する行を含む複数のデータフレームをマージするR

私はそれぞれ約40,000 - 60,000行の約150個の.csvファイルを持っています.3つの列を1つの大きなデータフレームにマージしようとしています。私は、各ファイルから関心のある3つのカラム( "id"、 "name"、 "value")を抽出し、大きなデータフレーム "MergedData"に "id"と "name"をマージする小さなスクリプトを持っています。

file_list <- list.files() 

for (file in file_list){ 

    if(!exists("MergedData")){ 
    MergedData <- read.csv(file, skip=5)[ ,c("id", "name", "value")] 
    colnames(MergedData) <- c("id", "name", file) 
    } 

    else if(exists("MergedData")){ 
    temp_data <- read.csv(file, skip=5)[ ,c("id", "name", "value")] 
    colnames(temp_data) <- c("id", "name", file) 
    MergedData <- merge(MergedData, temp_data, by=c("id", "name"), all=TRUE) 
    rm(temp_data) 
    } 
} 

必ずしもすべてのファイルがあります。ここに私のコード(!私はこれはこれを行うのは非常に非効率的な方法であると確信している、それは今の私と一緒に大丈夫ですが、もちろん、私はより良いオプションに開いている)であります同じ行数ですが、多くの行は多くのファイルに共通です。私は行の包括的なリストを持っていないので、MergedDataファイルにはまだ存在しない新しい行を追加するためにall = TRUEを含めました。

私の問題は:ファイルの多くは、同じ "ID"と "名前"エントリが異なる "値"エントリを持つ2-4行を含んでいます。だから私がそれらをマージすると、私は結局のところ手を抜く可能性のあるすべての組み合わせに対して行を追加することになります。最も不満は、これらの重複のどれも私にとって何の関心もないということです。最初のエントリの値を取得し、それ以上の重複エントリを無視する簡単な方法はありますか?

ありがとうございます!

答えて

0

あなたのコメントに基づいて、我々は、各ファイルを積み重ねることができ、その後、「ワイド」形式に「長い」から生じたデータフレームをキャスト:上記のコードで

library(dplyr) 
library(readr) 
library(reshape2) 

df = lapply(file_list, function(file) { 
      dat = read_csv(file) 
      dat$source.file = file 
      return(dat) 
     }) 
df = bind_rows(df) 
df = dcast(df, id + name ~ source.file, value.var="value") 

を、各ファイルに読み込んだ後、我々ファイル名(またはその変更バージョン)を含む新しい列source.fileを追加します。*次に、dcastを使用してデータフレームを "long"から "wide"形式にキャストし、各ファイルからvalueの個別の列を作成します。新しい列は、先ほど作成した名前の1つをsource.fileに持っています。

このデータフレームの処理内容によっては、後で分析するためにロングフォーマット(つまりdcastステップをスキップ)にする方が便利な場合があります。

補遺:対処方法Aggregation function missing: defaulting to length警告。これは、同じid,nameおよびsource.fileの行が複数ある場合に発生します。つまり、同じセルにマップされなければならない複数のvalueがあり、集約が行われます。デフォルトの集約関数は、length(すなわち、そのセル内の値の数のカウント)です。私が知っているこの唯一の方法は、(a)長い形式のデータを保持すること、(b)異なる集計関数を使用すること(例えば、mean)、または(c)余分なcounter列を追加して、 id,name、およびsource.fileの同じ組み合わせです。以下にこれらを示します。必要に応じて

df = data.frame(id=rep(1:2,2), 
       name=rep(c("A","B"), 2), 
       source.file=rep(c("001","002"), each=2), 
       value=11:14) 

df 
id name source.file value 
1 1 A   001 11 
2 2 B   001 12 
3 1 A   002 13 
4 2 B   002 14 
  1. idnamesource.fileの組み合わせごとに1つの値だけなので、dcast作品:

    まずは、いくつかの偽のデータを作成してみましょう。

    dcast(df, id + name ~ source.file, value.var="value") 
    
    id name 001 002 
    1 1 A 11 13 
    2 2 B 12 14 
    
  2. 同じidnamesource.fileで追加の行を追加します。現在、2つのセルが1つのセルにマップされるため、dcastは集約する必要があります。デフォルトの集約関数は、値の数のカウントを提供することです。

    df = rbind(df, data.frame(id=1, name="A", source.file="002", value=50)) 
    
    dcast(df, id + name ~ source.file, value.var="value") 
    
    Aggregation function missing: defaulting to length 
    
        id name 001 002 
    1 1 A 1 2 
    2 2 B 1 1 
    
  3. 代わりに、集約関数としてmeanを使用します。

    dcast(df, id + name ~ source.file, value.var="value", fun.aggregate=mean) 
    
    id name 001 002 
    1 1 A 11 31.5 
    2 2 B 12 14.0 
    
  4. が複数の行が同じidnamesource.fileであり、dcastにそれを含めるケースを区別するために、新しいcounter列を追加します。これにより、1セルあたり1つの値に戻ることができますが、source.fileには複数の列があることを犠牲にしています。

    # Add counter column 
    df = df %>% group_by(id, name, source.file) %>% 
        mutate(counter=1:n()) 
    

    あなたが見ることができるように、counter値はidname、およびsource.fileの唯一の1つの組み合わせがあります場合に1の値を持っていますが、ある一つのケースのための1と2の値を持ちますid,nameおよびsource.file(以下の3行目および5行目)の2行。 counter

    df 
    
     id name source.file value counter 
    1  1  A   001 11  1 
    2  2  B   001 12  1 
    3  1  A   002 13  1 
    4  2  B   002 14  1 
    5  1  A   002 50  2 
    

    dcast含まので、我々はsource.file "002" の2つの列を取得します。

    dcast(df, id + name ~ source.file + counter, value.var="value") 
    
    id name 001_1 002_1 002_2 
    1 1 A 11 13 50 
    2 2 B 12 14 NA 
    

*あなたはおそらくこれがユニークと命名フォーマットを作成調整する必要がありますので、私は、あなたのファイル名がどのように見えるかわからないんだけどファイル識別子。たとえば、ファイル名が "file001.csv"、 "file002.csv"などのパターンの場合は、dat$source.file = paste0("Value", gsub("file([0-9]{3})\\.csv", "\\1", file)とすることができます。

+0

私はこれを十分に説明したとは思わない。私の最終目標は、 "id"、 "name"という列を持つデータフレームであり、150個の各ファイルからの "value"の150列です。ファイルに "id" "name"というコンボの値がある場合は、それが必要です。私はそれらを積み重ね、重複した "ID" "名前"のエントリを削除し、関連するデータを削除しませんか? – JRoon

+0

更新されたコードを見て、それがあなたが探していたものに近いかどうか教えてください。 – eipi10

+0

これは近いです。 '> df = bind_rows(df)' 警告メッセージ: 1:rbind_all(x、.id):不一致要因レベル:文字に強制する 2:rbind_all(x、.id)で: df = dcast(df、id + name〜source.file、value.var = "value") ' '> df = dcast(集計関数がありません):デフォルトの長さです。結果として得られるデータフレームは構造化されていますが、値は実際には値そのものではなく、その行の各.csvファイルのエントリ数です。 – JRoon

関連する問題