-1

这是我之前的一个问题的后续,希望你能帮助我之前的问题: Recogning multiple IDs in a complex String with R

我有一个包含很多字符串和这样的值的数据框

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
...

String 也可以是这样,其中的 ID 应该允许为空或字符,像这样:

ID String                                                    Value
11  LocationID=123,321,345&TimeID=456,321,789&TypeID=         100
12  LocationID=123,345&TimeID=&TypeID=A                       50
13  LocationID=123,321,345&TypeID=32   
...

正如您在示例中看到的那样,“,”表示“或”。所以 locationID=123,321,345 指的是那些位置 ID 为 123、321 或 345 的元素。“值”可以被认为是满足字符串的条目数。

我想编写一个程序来使用 R 计算某些特定 ID 的出现次数。即程序的输出应该是:

sID  LocationID    TimeID    TypeID
1             3         3         2   #(String ID 1 have 3 Locaiotn ID, 3 TimeID and 2 TypeID)
2             2         2         0
...

我还需要计算两个不同 ID 的共存,比如

Condition          Co_existence
Location-Time               0.9   # How likely that I find a TimeID in the String, I will find a Location ID
Type-Time                   0.8   # How likely that I find a TimeID in the String, I will find a Type ID
......

谁能给我一些关于如何做这两个的建议?

4

2 回答 2

4

你会像上一个问题一样去:

  • 为每个字符串拆分
  • 将每个字符串拆分为其组件
  • 将 ID、字符串名称和组件收集到数据框中

示例代码:

# Beter share example data this way (directly usable in R)
df <- data.frame(ID = c(1, 2, 3, 11, 12, 13), stringsAsFactors=FALSE,
                 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",
                            "LocationID=123,321,345&TimeID=456,321,789&TypeID=",
                            "LocationID=123,345&TimeID=&TypeID=A",
                            "LocationID=123,321,345&TypeID=32"),
                 Values = c(100, 50, 120, 100, 50, NA))

# Get each String component in a list
df$splitString <- strsplit(df$String, split='&')

## Identify each String with the record ID before further processing
## (we will collect them out of the dataframe)
names(df$splitString) <- df$ID

# Split each component on [=, ] (*i.e.* split wherever there is an equal sign,
# a comma or a space). The first element is the name of the String, and the
# next elements are each possible value for it.
df$splitStringValues <- lapply(X=df$splitString, FUN=strsplit, split='[=, ]+')

# Be sure to explore the structure that we've got so far
str(df)

接下来创建一个包含以下变量的数据框:

  • ID:原始ID
  • StringName:不同字符串的名称(LocationID、TimeID
  • StringValue:每个字符串的可能值。

从这个数据框你应该能够得到你想要的所有信息。


编辑:按照 Arun 的建议,我完成了请求的分析。为什么 OP 会变得有趣?我添加了一个步骤并修改了数据,所以也检查一下。新代码如下:

# Processing the list is much easier with plyr
library(package=plyr)

# You take the list of strings, and for each string get the values
# (all but the first, which is the name of the string), record the
# name of the string for each value, and collect everything in a dataframe.
# For empty strings set NA.
strings <- ldply(.data=df$splitStringValues,
                 .fun=function(record){
                    ldply(.data=record,
                          .fun=function(string){
                             if(length(string)>1){
                                .tmp <- data.frame(Val=string[-1])
                                .tmp <- cbind(String=string[1], .tmp)
                             } else {
                                .tmp <- data.frame(Val=NA, String=string[1])
                             }
                             .tmp
                     })
            })

# Count values in each string
table(strings$String, strings$.id)

# And calculate co-ocurrence.
co_ocurrence <-
   ddply(.data=strings, .variables='.id',
         .fun=function(x){
           data.frame(Combinations=combn(unique(x$String), m=2, paste, collapse='-'))
   })
prop.table(table(co_ocurrence$Combinations))
于 2013-02-20T07:14:53.860 回答
0

感谢您的所有宝贵意见和建议。最后,我使用了以下代码来完成我的任务。

我不是一个好的程序员,而且大多只能使用一些蛮力算法来处理我的问题。我总是想请像你们这样的专家在我的工作中学习一些更聪明的方法。

我对 R 很陌生,我想。我总是对“列表”、“数据框”等概念感到困惑……还有 lapply、mapply……当问题涉及 RegEx 时,情况更糟……我很荣幸拥有所有这些你在 Stack Overflow Society 给我的建议。

我确实认为我从你们那里学到了很多东西

以下是我用来处理真实数据的最终代码,如果您有更聪明的方法,请再次给我您的建议。

一次又一次的感谢。

##### Clear things to start #####
rm(list=ls(all=TRUE))

#### Testing Data Frame ####
df <- data.frame(ID = c(1, 2, 3, 11, 12, 13), stringsAsFactors=FALSE,
             String = c("LocationID=123,321,345&TimeID=456,321,789&TypeID=12,32&DummyID=969",
                        "LocationID=123,345&TimeID=456,321&DummyID=969",
                        "LocationID=123,321,345&TypeID=32&DummyID=969",
                        "LocationID=123,321,345&TimeID=456,321,789&TypeID=&DummyID=969",
                        "LocationID=123,345&TimeID=&TypeID=A&DummyID=969",
                        "LocationID=123,321,345&TypeID=32&DummyID=969"),
             Values = c(100, 50, 120, 100, 50, NA))
# The wanted IDs
fields <- c("LocationID", "TimeID", "TypeID")
outFile <- "./Co_occurence.xlsx"

#### Main Program ####
# Get each String component in a list
df$splitString <- strsplit(df$String, split='&')

## Identify each String with the record ID before further processing
## (we will collect them out of the dataframe)
names(df$splitString) <- df$ID

# Split each component on [=, ] (*i.e.* split wherever there is an equal sign,
# a comma or a space). The first element is the name of the String, and the
# next elements are each possible value for it.
df$splitStringValues <- lapply(X=df$splitString, FUN=strsplit, split='[=, ]+')

# Processing the list is much easier with plyr
library(package=plyr)

# You take the list of strings, and for each string get the values
# (all but the first, which is the name of the string), record the
# name of the string for each value, and collect everything in a dataframe.
# For empty strings set NA.
strings <- ldply(.data=df$splitStringValues,
             .fun=function(record){
               ldply(.data=record,
                     .fun=function(string){
                       if(length(string)>1){
                         .tmp <- data.frame(Val=string[-1])
                         .tmp <- cbind(String=string[1], .tmp)
                       } else {
                         # Set String = NA if Value is Empty
                         # Otherwise will get 1 for entries like ID2 in "ID1=123&ID2=&ID3=456"
                         .tmp <- data.frame(Val=NA, String=NA)
                       }
                       .tmp
                     })
             })

# Remove those unwanted IDs
finalStrings <- strings[strings$String %in% fields,]
finalStrings$String <- factor(finalStrings$String)

# Count values in each string
OutStrings <- as.data.frame.matrix(table(finalStrings$.id, finalStrings$String))
OutStrings$ID <- rownames(OutStrings)
OutStrings <- merge(df[,c("ID", "String", "Values")], 
                OutStrings, by="ID")
OutStrings$Total <- rowSums(OutStrings[,4:ncol(OutStrings)],)
OutStrings$nFields<- rowSums(OutStrings[,4:ncol(OutStrings)]!=0,)
OutStrings <- OutStrings[with(OutStrings, order(-OutStrings$Value)), ]

# Count the total occurrence for different number of conditions used
OutDistrTotal <- aggregate(Values~Total, sum, data=OutStrings)
OutDistrTotal <- OutDistrTotal[with(OutDistrTotal, order(-OutDistrTotal$Values)),]

# Count the total occurrence for different number of Fields used
OutDistrnFields <- aggregate(Values~nFields, sum, data=OutStrings)
OutDistrnFields <- OutDistrnFields[with(OutDistrnFields, order(-OutDistrnFields$Values)),]

# And calculate co-ocurrence.
co_ocurrence <- ddply(.data=finalStrings, .variables='.id',
    .fun=function(x){
      data.frame(Combinations=combn(unique(x$String), m=2, paste, collapse='-'))
    })
Outcooccurrence <- data.frame(prop.table(table(co_ocurrence$Combinations)))
Outcooccurrence <- Outcooccurrence[with(Outcooccurrence, order(-Outcooccurrence$Freq)),]

library("xlsx")
write.xlsx(OutStrings, outFile, "Strings", append=F, row.names = FALSE)
write.xlsx(OutDistrTotal, outFile, "DistrTotal", append=T, row.names = FALSE)
write.xlsx(OutDistrnFields, outFile, "OutDistrnFields", append=T, row.names = FALSE)
write.xlsx(Outcooccurrence, outFile, "Outcooccurrence", append=T, row.names = FALSE)
于 2013-02-21T04:43:56.297 回答