2

両方に存在する「日時」列を使用して 2 つのデータセットをマージしたいと考えています (POSIXct 形式: dd/mm/yyyy hh:mm)。以下は、2 つのデータセットからのサンプル データです。

# Dataset 1 (dts1)

           datetime   count   period   
1  30/03/2011 02:32      27      561
2  30/03/2011 02:42       3      600
3  30/03/2011 02:52       0      574
4  30/03/2011 03:02       1      550
5  30/03/2011 03:12      15      600
6  30/03/2011 03:22       0      597

# Dateset 2 (dts2)

   datetime         dist car   satd      alt
1 30/03/2011 01:59  23.9   1      3     1.76       
2 30/03/2011 02:58  14.7   1      7     6.36       
3 30/03/2011 03:55  10.4   2      9    -0.34      
4 30/03/2011 04:53  35.4   1      3     3.55      
5 30/03/2011 05:52  56.1   1      7    -0.91       
6 30/03/2011 06:48  12.3   1      4     6.58      
7 30/03/2011 07:48  10.7   1      5     4.18      

2 つのフレームから一致する行をマージする単純なケースである場合は、basicmerge(data1, data2, by="datetime")またはrbind()function を使用できます。

ただし、 2 つのデータセットの時間間隔が等しくないため、私の問題はより複雑です。正確なDataset 110 分間隔のデータが含まれています (各行には、指定された日時で終了する 10 分ブロックに関する情報が組み込まれています)、おおよそ1 時間間隔のデータが含まれています (各行には、指定された日付/時刻で終了する 1 時間ブロックの情報が組み込まれています)。指定された日時に終了します)。dataset 2

さらに困難なことに、2 つのデータセットの行の開始時間には時間の不一致dts1があります (つまり、2013 年 1 月 3日dts210:00:00、2012 年 1 月 3 日 09:58:12)。dts2間隔もデータセット全体で異なります (± 1 時間の両側で数分)。データセット 1 の 10 分ごとのデータ行を、データセット 2 に収まる時間ブロックにリンクしたいと考えています (dts2 からの関連するすべての列値とともに)。2 つの異なる時間ブロック (つまり、2011 年 3 月 30 日 03:02) に収まる行がいくつかありますが、これらの行を時間ブロックの 1 つにリンクするだけで済みます。

私はこのようなもので終わりたいと思います:

        datetime_dts1 count period     datetime2_dts2  dist  car satd      alt  
1    30/03/2011 02:32    27    561   30/03/2011 02:58  14.7   1     7     6.36      
2    30/03/2011 02:42     3    600   30/03/2011 02:58  14.7   1     7     6.36
3    30/03/2011 02:52     0    574   30/03/2011 02:58  14.7   1     7     6.36
4    30/03/2011 03:02     1    550   30/03/2011 02:58  14.7   1     7     6.36
5    30/03/2011 03:12    15    600   30/03/2011 03:55  10.4   2     9    -0.34
6    30/03/2011 03:22     0    597   30/03/2011 03:55  10.4   2     9    -0.34

この問題に対する答えを探しましたが、解決できず、R の能力も高くありません。誰かが私に方向性や解決策を提供してくれたら、とても感謝しています.

4

2 に答える 2

6

最初に日時文字列をPOSIXtクラスに変換した後、それらの時間をrounding とtruncating を組み合わせてマージの基礎として使用できるものを取得する必要があります。

最初にデータを読み込み、対応する POSIXt 日時を作成します。

dts1 <- structure(list(datetime = structure(1:6,
   .Label = c("30/03/2011 02:32", "30/03/2011 02:42",
   "30/03/2011 02:52", "30/03/2011 03:02", "30/03/2011 03:12",
   "30/03/2011 03:22"), class = "factor"), count = c(27L, 3L,
   0L, 1L, 15L, 0L), period = c(561L, 600L, 574L, 550L, 600L,
   597L)), .Names = c("datetime", "count", "period"),
   class = "data.frame", row.names = c(NA, -6L))
dts2 <- structure(list(datetime = structure(1:7,
    .Label = c("30/03/2011 01:59", "30/03/2011 02:58",
    "30/03/2011 03:55", "30/03/2011 04:53", "30/03/2011 05:52",
    "30/03/2011 06:48", "30/03/2011 07:48"), class = "factor"),
    dist = c(23.9, 14.7, 10.4, 35.4, 56.1, 12.3, 10.7), car =
    c(1L, 1L, 2L, 1L, 1L, 1L, 1L), satd = c(3L, 7L, 9L, 3L, 7L,
    4L, 5L), alt = c(1.76, 6.36, -0.34, 3.55, -0.91, 6.58,
    4.18)), .Names = c("datetime", "dist", "car", "satd",
    "alt"), class = "data.frame", row.names = c(NA, -7L))

# create corresponding POSIXlt vector
# (you could update the 'datetime' columns in-place if you prefer)
datetime1 <- strptime(dts1$datetime, format="%d/%m/%Y %H:%M")
datetime2 <- strptime(dts2$datetime, format="%d/%m/%Y %H:%M")

次のコードは、すべてのケースで最も近い時間に基づいてマージされたテーブルを生成します。マージの内部では、各データ フレームに丸められた時間を含む列を先頭に追加し、それに基づいてマージし (つまり、列番号 1)、-1インデックスを使用して最後にその列を削除します。

# merge based on nearest hour
merge(
    cbind(round(datetime1, "hours"), dts1),
    cbind(round(datetime2, "hours"), dts2),
    by=1, suffixes=c("_dts1", "_dts2")
)[-1]

     datetime_dts1 count period    datetime_dts2 dist car satd  alt
1 30/03/2011 02:32    27    561 30/03/2011 02:58 14.7   1    7 6.36
2 30/03/2011 02:42     3    600 30/03/2011 02:58 14.7   1    7 6.36
3 30/03/2011 02:52     0    574 30/03/2011 02:58 14.7   1    7 6.36
4 30/03/2011 03:02     1    550 30/03/2011 02:58 14.7   1    7 6.36
5 30/03/2011 03:12    15    600 30/03/2011 02:58 14.7   1    7 6.36
6 30/03/2011 03:22     0    597 30/03/2011 02:58 14.7   1    7 6.36

上記と同じですが、今回は時間で切り捨てます:

merge(
    cbind(trunc(datetime1, "hours"), dts1),
    cbind(trunc(datetime2, "hours"), dts2),
    by=1, suffixes=c("_dts1", "_dts2")
)[-1]

     datetime_dts1 count period    datetime_dts2 dist car satd   alt
1 30/03/2011 02:32    27    561 30/03/2011 02:58 14.7   1    7  6.36
2 30/03/2011 02:42     3    600 30/03/2011 02:58 14.7   1    7  6.36
3 30/03/2011 02:52     0    574 30/03/2011 02:58 14.7   1    7  6.36
4 30/03/2011 03:02     1    550 30/03/2011 03:55 10.4   2    9 -0.34
5 30/03/2011 03:12    15    600 30/03/2011 03:55 10.4   2    9 -0.34
6 30/03/2011 03:22     0    597 30/03/2011 03:55 10.4   2    9 -0.34

上記と同様ですが、dts1 の場合、切り捨てる前に 10*60 秒を減算することにより、正時から 10 分後までレコードを前の時間に属するものとして扱います。これはあなたが指定したものと同じ出力を生成しますが、それ以上の情報がなければ、それがあなたが望む正確なルールであるかどうかはわかりません.

merge(
    cbind(trunc(datetime1 - 10*60, "hours"), dts1),
    cbind(trunc(datetime2, "hours"), dts2),
    by=1, suffixes=c("_dts1", "_dts2")
)[-1]

     datetime_dts1 count period    datetime_dts2 dist car satd   alt
1 30/03/2011 02:32    27    561 30/03/2011 02:58 14.7   1    7  6.36
2 30/03/2011 02:42     3    600 30/03/2011 02:58 14.7   1    7  6.36
3 30/03/2011 02:52     0    574 30/03/2011 02:58 14.7   1    7  6.36
4 30/03/2011 03:02     1    550 30/03/2011 02:58 14.7   1    7  6.36
5 30/03/2011 03:12    15    600 30/03/2011 03:55 10.4   2    9 -0.34
6 30/03/2011 03:22     0    597 30/03/2011 03:55 10.4   2    9 -0.34

特定のルールに応じて、丸めるもの、切り捨てるもの、および最初に時間を減算/加算するかどうかの詳細を微調整できます。

編集:

最もエレガントではありませんが、コメントで説明したより複雑な条件付きルールに対応する別のアプローチを次に示します。これna.locfは、zoo パッケージに大きく依存して、各 dts1 レコードの前後にある dts2 時刻を最初に判別します。これらが手元にあれば、ルールを適用して目的の dts2 時刻を選択し、元の dts1 テーブルに照合してからマージするだけです。

library(zoo)

# create ordered list of all datetimes, using names to keep
# track of which ones come from each data frame
alldts <- sort(c(
    setNames(datetime1, rep("dts1", length(datetime1))),
    setNames(datetime2, rep("dts2", length(datetime2)))))
is.dts1 <- names(alldts)=="dts1"

# for each dts1 record, get previous closest dts2 time
dts2.prev <- alldts
dts2.prev[is.dts1] <- NA
dts2.prev <- na.locf(dts2.prev, na.rm=FALSE)[is.dts1]

# for each dts1 record, get next closest dts2 time
dts2.next <- alldts
dts2.next[is.dts1] <- NA
dts2.next <- na.locf(dts2.next, na.rm=FALSE, fromLast=TRUE)[is.dts1]

# for each dts1 record, apply rule to choose dts2 time
use.prev <- !is.na(dts2.prev) & (alldts[is.dts1] - dts2.prev < 5)
dts2.to.use <- ifelse(use.prev, as.character(dts2.prev), 
    as.character(dts2.next))

# merge based on chosen dts2 times, prepended as character vector
# for the purpose of merging
merge(
    cbind(.dt=dts2.to.use[match(datetime1, alldts[is.dts1])], dts1),
    cbind(.dt=as.character(datetime2), dts2),
    by=".dt", all.x=TRUE, suffixes=c("_dts1", "_dts2")
)[-1]
于 2013-03-04T15:26:48.613 に答える