Saya memiliki dua data.frame
s dengan beberapa kolom yang umum (di sini: date
, city
, ctry
, dan ( other_
) number
).
Sekarang saya ingin menggabungkan mereka pada kolom di atas tetapi mentolerir beberapa tingkat perbedaan:
threshold.numbers <- 3
threshold.date <- 5 # in days
Jika perbedaan antara date
entri adalah > threshold.date
(dalam hari) atau > threshold.numbers
, saya tidak ingin garis digabungkan. Demikian pula, jika entri dalam city
adalah substring dari df
entri orang lain di city
kolom, saya ingin garis digabungkan. [Jika ada yang punya ide yang lebih baik untuk menguji kesamaan nama kota yang sebenarnya, saya akan senang mendengarnya.] (Dan menyimpan df
entri pertama dari date
, city
dan country
tetapi kedua ( other_
) number
kolom dan semua kolom lainnya di df
.
Perhatikan contoh berikut:
df1 <- data.frame(date = c("2003-08-29", "1999-06-12", "2000-08-29", "1999-02-24", "2001-04-17",
"1999-06-30", "1999-03-16", "1999-07-16", "2001-08-29", "2002-07-30"),
city = c("Berlin", "Paris", "London", "Rome", "Bern",
"Copenhagen", "Warsaw", "Moscow", "Tunis", "Vienna"),
ctry = c("Germany", "France", "UK", "Italy", "Switzerland",
"Denmark", "Poland", "Russia", "Tunisia", "Austria"),
number = c(10, 20, 30, 40, 50, 60, 70, 80, 90, 100),
col = c("apple", "banana", "pear", "banana", "lemon", "cucumber", "apple", "peach", "cherry", "cherry"))
df2 <- data.frame(date = c("2003-08-29", "1999-06-12", "2000-08-29", "1999-02-24", "2001-04-17", # all identical to df1
"1999-06-29", "1999-03-14", "1999-07-17", # all 1-2 days different
"2000-01-29", "2002-07-01"), # all very different (> 2 weeks)
city = c("Berlin", "East-Paris", "near London", "Rome", # same or slight differences
"Zurich", # completely different
"Copenhagen", "Warsaw", "Moscow", "Tunis", "Vienna"), # same
ctry = c("Germany", "France", "UK", "Italy", "Switzerland", # all the same
"Denmark", "Poland", "Russia", "Tunisia", "Austria"),
other_number = c(13, 17, 3100, 45, 51, 61, 780, 85, 90, 101), # slightly different to very different
other_col = c("yellow", "green", "blue", "red", "purple", "orange", "blue", "red", "black", "beige"))
Sekarang, saya ingin menggabungkan data.frames
dan menerima di df
mana garis digabungkan jika kondisi di atas terpenuhi.
(Kolom pertama hanya untuk kenyamanan Anda: di belakang digit pertama, yang menunjukkan case asli, ini menunjukkan apakah garis tempat digabungkan ( .
) atau apakah garis berasal df1
( 1
) atau df2
( 2
).
date city ctry number other_col other_number other_col2 #comment
1. 2003-08-29 Berlin Germany 10 apple 13 yellow # matched on date, city, number
2. 1999-06-12 Paris France 20 banana 17 green # matched on date, city similar, number - other_number == threshold.numbers
31 2000-08-29 London UK 30 pear <NA> <NA> # not matched: number - other_number > threshold.numbers
32 2000-08-29 near London UK <NA> <NA> 3100 blue #
41 1999-02-24 Rome Italy 40 banana <NA> <NA> # not matched: number - other_number > threshold.numbers
42 1999-02-24 Rome Italy <NA> <NA> 45 red #
51 2001-04-17 Bern Switzerland 50 lemon <NA> <NA> # not matched: cities different (dates okay, numbers okay)
52 2001-04-17 Zurich Switzerland <NA> <NA> 51 purple #
6. 1999-06-30 Copenhagen Denmark 60 cucumber 61 orange # matched: date difference < threshold.date (cities okay, dates okay)
71 1999-03-16 Warsaw Poland 70 apple <NA> <NA> # not matched: number - other_number > threshold.numbers (dates okay)
72 1999-03-14 Warsaw Poland <NA> <NA> 780 blue #
81 1999-07-16 Moscow Russia 80 peach <NA> <NA> # not matched: number - other_number > threshold.numbers (dates okay)
82 1999-07-17 Moscow Russia <NA> <NA> 85 red #
91 2001-08-29 Tunis Tunisia 90 cherry <NA> <NA> # not matched: date difference < threshold.date (cities okay, dates okay)
92 2000-01-29 Tunis Tunisia <NA> <NA> 90 black #
101 2002-07-30 Vienna Austria 100 cherry <NA> <NA> # not matched: date difference < threshold.date (cities okay, dates okay)
102 2002-07-01 Vienna Austria <NA> <NA> 101 beige #
Saya mencoba berbagai implementasi penggabungan tetapi tidak dapat menerapkan ambang.
Permintaan Maaf EDIT untuk formulasi tidak jelas - Saya ingin mempertahankan semua baris dan menerima indikator apakah baris cocok, tidak cocok dan dari df1 atau tidak cocok dan dari df2.
pseudo-code adalah:
if there is a case where abs("date_df2" - "date_df1") <= threshold.date:
if "ctry_df2" == "ctry_df1":
if "city_df2" ~ "city_df1":
if abs("number_df2" - "number_df1") <= threshold.numbers:
merge and go to next row in df2
else:
add row to df1```
.
?Jawaban:
Inilah solusi yang menggunakan safejoin paket saya , membungkus dalam hal ini paket fuzzyjoin .
Kita dapat menggunakan
by
argumen untuk menentukan kondisi yang kompleks, menggunakan fungsiX()
untuk mendapatkan nilai daridf1
, danY()
untuk mendapatkan nilai daridf2
.Jika tabel asli Anda besar, ini mungkin lambat atau tidak mungkin karena ia menghasilkan produk cartesian, tetapi di sini ia berfungsi dengan baik.
Yang kami inginkan adalah bergabung penuh (pertahankan semua baris, dan bergabunglah dengan apa yang bisa digabungkan), dan kami ingin mempertahankan nilai pertama ketika mereka bergabung, dan mengambil yang berikutnya dengan bijak, ini berarti kami ingin menangani konflik kolom dinamai identik dengan penggabungan, jadi kami menggunakan argumen
conflict = dplyr::coalesce
keluaran:
Dibuat pada 2019-11-13 oleh paket reprex (v0.3.0)
Sayangnya fuzzyjoin memaksa semua kolom dalam matriks ketika melakukan multi join, dan safejoin membungkus fuzzyjoin sehingga kita harus mengonversi variabel ke tipe yang sesuai di dalam argumen, ini menjelaskan baris pertama dalam
by
argumen.Lebih lanjut tentang safejoin : https://github.com/moodymudskipper/safejoin
sumber
Saya pertama-tama mengubah nama kota menjadi vektor karakter, karena (jika saya mengerti dengan benar) Anda ingin memasukkan nama kota yang terdapat dalam df2.
Kemudian gabungkan mereka menurut negara:
Perpustakaan
stringr
akan memungkinkan Anda untuk melihat apakah city.x ada di dalam city.y di sini (lihat kolom terakhir):Maka Anda bisa mendapatkan perbedaan hari antara tanggal:
dan perbedaan angka:
Inilah tampilan kerangka data yang dihasilkan:
Tapi kami ingin meletakkan hal-hal di mana city.x tidak ditemukan di dalam city.y, di mana perbedaan hari lebih besar dari 5 atau perbedaan angka lebih besar dari 3:
Yang tersisa adalah tiga baris yang Anda miliki di atas (yang berisi titik-titik di kolom 1).
Sekarang kita bisa menjatuhkan tiga kolom yang kita buat, dan tanggal dan kota dari df2:
sumber
Langkah 1: Menggabungkan data berdasarkan "kota" dan "ctry":
Langkah 2: Hapus baris jika perbedaan antara entri tanggal> threshold.date (dalam hari):
Langkah 3: Hapus baris jika perbedaan antara angka adalah> threshhold.number:
Data harus digabung sebelum menerapkan kondisi, jika baris tidak cocok.
sumber
Opsi menggunakan
data.table
(penjelasan sebaris):keluaran:
sumber
Anda dapat menguji
city
pertandingan dengangrepl
danctry
dengan sederhana==
. Bagi mereka yang cocok hingga di sini Anda dapat menghitung perbedaan tanggal dengan mengonversidate
menggunakanas.Date
dan membandingkannya dengan adifftime
. Thenumber
Perbedaan ini dilakukan dengan cara yang sama.sumber
Berikut ini adalah pendekatan fleksibel yang memungkinkan Anda menentukan kumpulan kriteria penggabungan yang Anda pilih.
Persiapan kerja
Saya memastikan bahwa semua string
df1
dandf2
string, bukan faktor (seperti dicatat dalam beberapa jawaban lainnya). Saya juga membungkus kurmaas.Date
untuk membuat mereka kencan nyata.Tentukan kriteria gabungan
Buat daftar daftar. Setiap elemen dari daftar utama adalah satu kriteria; anggota kriteria adalah
final.col.name
: nama kolom yang kita inginkan di tabel akhircol.name.1
: nama kolom didf1
col.name.2
: nama kolom didf2
exact
: boolean; haruskah kita melakukan pencocokan tepat pada kolom ini?threshold
: threshold (jika kami tidak melakukan pencocokan tepat)match.function
: fungsi yang mengembalikan apakah baris cocok atau tidak (untuk kasus khusus seperti menggunakangrepl
untuk pencocokan string; perhatikan bahwa fungsi ini harus di -vektor)Berfungsi untuk menggabungkan
Fungsi ini membutuhkan tiga argumen: dua frame data yang ingin kami gabungkan, dan daftar kriteria kecocokan. Itu hasil sebagai berikut:
Terapkan fungsinya, dan kita selesai
sumber