1

文字列が多く、このような値のデータフレームがあります

ID String                                                    Value
1  LocationID=123,321,345&TimeID=456,321,789&TypeID=12,32    100
2  LocationID=123,345&TimeID=456,321                         50
3  LocationID=123,321,345&TypeID=32                          120
...

例でわかるように、「、」は「または」を意味します。したがって、locationID = 123,321,345は、ロケーションID 123、321、または345を持つ要素を指します。「値」は、文字列を満たすエントリの数と考えることができます。

Rを使用して各IDの発生数を計算するプログラムを作成したいと思います。つまり、プログラムの出力は次のようになります。

ID                Occurrence
LocationID = 123  270                          #(100+50+120)
LocationID = 321  220                          #(100+120)
...
TypeID = 12       100
...

誰かが私にこのタスクを行う方法についていくつかの提案を与えることができますか?

「、」とIDの扱いが非常に難しいことがわかりました。それ以外の場合は、forループを使用できますが、forループは嫌いです。

さらに問題として、IDは次のように空または文字を許可する必要があります。

ID String                                                    Value
1  LocationID=123,321,345&TimeID=456,321,789&TypeID=         100
2  LocationID=123,345&TimeID=&TypeID=A                       50
3  LocationID=123,321,345&TypeID=32                          120
4

4 に答える 4

5

これを試して。 rbind がその後の結果であることを除いてlapply2は似ています。lapplyString 引数を分割し、結果を に入れsます。dat2次に、ID ごとに 1 つの行を持つ新しいデータ フレームを計算します。サンプル データの場合、行 1 に 3 つの ID、行 2 に 2 つの ID、行 3 に 2 つの ID があるため、dat23+2+2 = 7 行になります。同様に、爆発dat2して を生成しdat3ます。その一環として、strapplycすべてのオカレンスの抽出を簡素化するために使用します。最後に、 を使用aggregateして結果を計算します。

library(gsubfn)

lapply2 <- function(...) do.call("rbind", lapply(...))

s <- strsplit(dat$String, "&")

dat2 <- lapply2(1:nrow(dat), function(i) 
     data.frame(
            String = I(s[[i]]), 
            Value = dat$Value[i]
     )
)

dat3 <- lapply2(1:nrow(dat2), function(i) 
     data.frame(
            String = sub("=.*", "", dat2$String[i]), 
            Occurrence = strapplyc(dat2$String[i], "\\d+")[[1]], 
            Value = dat2$Value[i]
     )
)

ag <- aggregate(Value ~ String + Occurrence, dat3, sum)

結果は次のとおりです。

> ag
      String Occurrence Value
1 LocationID        123   270
2 LocationID        321   220
3     TimeID        321   150
4 LocationID        345   270
5     TimeID        456   150
6     TimeID        789   100
7     TypeID         12   100
8     TypeID         32   220
于 2013-02-05T06:08:56.660 に答える
2

G. Grothendieck の回答の方がはるかに優れていますが、私はすでに解決策に取り組み始めていたので、ここにあります。これはベース R に固執し、長いlapply. データの名前が「mydata」であると仮定します。

まず、「文字列」列をアンパサンドで分割します

temp1 <- strsplit(mydata$String, "&")

次に、 in と呼ばれる複雑な無名関数がありlapplyます。何が起こっているかを確認できるように、手順に注釈を付けました。

temp2 <- do.call(
  "rbind", 
  lapply(seq_along(temp1), function(x) {
    # Set the pattern we're going to look for
    pattern <- "(.*)=(.*)"
    # Extract names and values
    Name <- gsub(pattern, "\\1", temp1[[x]])
    Measure <- gsub(pattern, "\\2", temp1[[x]])
    # Split the Measure value, and create a data.frame
    Output <- lapply(strsplit(Measure, ","), function(x) 
      data.frame(as.numeric(x)))
    names(Output) <- Name             # Add the names back to the list
    Output <- do.call(rbind, Output)  # rbind the sub-lists
    # Move the rownames to a column
    Output$Param <- gsub("(.*)\\.[0-9]+", "\\1", rownames(Output))
    rownames(Output) <- NULL          # Clean up the rownames
    names(Output)[1] <- "Measure"     # Rename the measure variable
    # Make a nice dataframe with your original data too.
    data.frame(ID = mydata[x, "ID"], Output, Value = mydata[x, "Value"])
  }))

結果は次のようになります。

temp2
#    ID Measure      Param Value
# 1   1     123 LocationID   100
# 2   1     321 LocationID   100
# 3   1     345 LocationID   100
# 4   1     456     TimeID   100
# 5   1     321     TimeID   100
# 6   1     789     TimeID   100
# 7   1      12     TypeID   100
# 8   1      32     TypeID   100
# 9   2     123 LocationID    50
# 10  2     345 LocationID    50
# 11  2     456     TimeID    50
# 12  2     321     TimeID    50
# 13  3     123 LocationID   120
# 14  3     321 LocationID   120
# 15  3     345 LocationID   120
# 16  3      32     TypeID   120

aggregateしたがって、これを取得するために出力で簡単に使用できます。

aggregate(Value ~ Param + Measure, temp2, sum)
#        Param Measure Value
# 1     TypeID      12   100
# 2     TypeID      32   220
# 3 LocationID     123   270
# 4 LocationID     321   220
# 5     TimeID     321   150
# 6 LocationID     345   270
# 7     TimeID     456   150
# 8     TimeID     789   100

便宜上、dputデータの最初の数行を次に示します。

mydata <- structure(list(ID = 1:3, 
                         String = c("LocationID=123,321,345&TimeID=456,321,789&TypeID=12,32",
                                    "LocationID=123,345&TimeID=456,321", 
                                    "LocationID=123,321,345&TypeID=32"), 
                         Value = c(100L, 50L, 120L)), 
                    .Names = c("ID", "String", "Value"), 
                    row.names = c(NA, -3L), 
                    class = "data.frame")
于 2013-02-05T07:24:05.247 に答える
1

strsplit 関数を使用してみてください。文字列を次のようにトークン化できます

strsplit("LocationID=123,321,345&TimeID=456,321,789&TypeID=12,32","&"); ## this will tokenize by splitting by &;

次に、grep を使用して LocationID、TimeID、TypeID の存在を確認し、「=」と「,」で適切に strsplit して、値を補助フレームに追加します。

最後に「tapply」を呼び出します

これが大まかな概要として役立つことを願っています

于 2013-02-05T04:40:34.757 に答える
1

このようなことができます

dat <- read.table(text = 'ID String                                                    Value
1  LocationID=123,321,345&TimeID=456,321,789&TypeID=12,32    100
2  LocationID=123,345&TimeID=456,321                         50
3  LocationID=123,321,345&TypeID=32                          120',header= T, stringsAsFactors=F)
## split by &
ll <- unlist(strsplit(dat$String,'&'))
## create 2 lits of occuonces and id names
occs <- strsplit(gsub('(.*)ID=(.*)','\\2',ll),',')
ids <- gsub('(.*)ID=(.*)','\\1',ll)
names(occs) <- ids
ll <- sapply(names(occs),function(x) occs[x] <- paste(x,occs[[x]], sep ='_'))
## use rapply to change list in data.frame then count by table
table(rapply(ll,I))

Location_123 Location_321 Location_345     Time_321     Time_456     Time_789      Type_12      Type_32 
           3            3            3            2            2            2            2            2 
于 2013-02-05T04:51:41.107 に答える