【问题标题】:Looping and adding to a counter in R循环并添加到R中的计数器
【发布时间】:2015-04-02 09:42:05
【问题描述】:

我有一个数据框df,其中包含几列,但下面给出了唯一相关的列。

node    |   precedingWord
-------------------------
A-bom       de
A-bom       die
A-bom       de
A-bom       een
A-bom       n
A-bom       de
acroniem    het
acroniem    t
acroniem    het
acroniem    n
acroniem    een
act         de
act         het
act         die
act         dat
act         t
act         n

我想使用这些值来计算每个节点的precedingWords,但带有子类别。例如:要添加值的一列标题为neuter,另一列为non-neuter,最后一列为restneuter 将包含所有值,previousWord 是以下值之一:t,het,datnon-neuter 将包含 dedie,rest 将包含不属于 neuternon-neuter 的所有内容。 (如果这可以是动态的,那就太好了,换句话说,rest 使用了某种用于中性和非中性的反转变量。或者只是从长度中减去中性和非中性的值具有该节点的行。)

示例输出(在一个新的数据帧中,比如说freqDf,看起来像这样:

node    |   neuter   | nonNeuter   | rest
-----------------------------------------
A-bom       0          4             2
acroniem    3          0             2
act         3          2             1

要创建freqDf$node,我可以这样做:

freqDf<- data.frame(node = unique(df$node), stringsAsFactors = FALSE)

但这已经是我的全部了;我不知道如何继续。我想我可以做这样的事情,但不幸的是 ++ 运算符没有像我希望的那样工作。

freqDf$neuter[grep("dat|het|t", df$precedingWord, perl=TRUE)] <- ++
freqDf$nonNeuter[grep("de|die", df$precedingWord, perl=TRUE)] <- ++

e <- table(df$Node)
freqDf$rest <- as.numeric(e - freqDf$neuter - freqDf$nonNeuter)

此外,这不适用于单独的每个节点。我需要某种循环,自动为freqDf$node 中的每个不同值运行。

【问题讨论】:

  • 一个丑陋的解决方案 data.table: dt&lt;-as.data.table(df);dt[,list(neuter=sum(precedingWord %in% c("t","het","dat")),nonNeuter=sum(precedingWord %in% c("de","die")),rest=sum(!precedingWord %in% c("t","het","dat","de","die"))),by=node].
  • @nicola 我收到回复 dat as.data.table is not a function。
  • 对不起,我没有指定你需要data.table 包。安装它,然后把require(data.table)放在我写的上面。

标签: r loops counter


【解决方案1】:

一种方法是用它们的类别替换值,然后使用table函数生成频率。

neuter <- c("t", "het", "dat")
non.neuter <- c("de", "die")

df$precedingWord[df$precedingWord %in% neuter] <- "neuter"
df$precedingWord[df$precedingWord %in% non.neuter] <- "non.neuter"
df$precedingWord[!df$precedingWord %in% c(neuter, non.neuter)] <- "rest"

table(df)

      precedingWord
  node       neuter non.neuter rest
  A-bom         0          4    2
  acroniem      3          0    2
  act           3          2    1

但我确信使用 dplyr 包会有更好的解决方案。

编辑:也许是这样的: (它不会覆盖您的“precedingWord”列,而是添加一个新的“gender”)

library(dplyr)
df %>%
  mutate(gender = ifelse(!precedingWord %in% c(neuter, non.neuter), "rest", 
                         ifelse(precedingWord %in% neuter, "neuter", "non.neuter"))) %>%
  count(node, gender)


Source: local data frame [7 x 3]
Groups: node

      node     gender n
1    A-bom non.neuter 4
2    A-bom       rest 2
3 acroniem     neuter 3
4 acroniem       rest 2
5      act     neuter 3
6      act non.neuter 2
7      act       rest 1

# And if you want the same output you put in your question, you can use table
df2 <- mutate(df, gender = ifelse(!precedingWord %in% c(neuter, non.neuter), "rest", 
                       ifelse(precedingWord %in% neuter, "neuter", "non.neuter")))

table(df2$node, df2$gender)

           neuter non.neuter rest
  A-bom         0          4    2
  acroniem      3          0    2
  act           3          2    1

编辑:将表格转换为可操作的数据框

myTable <- table(df2$node, df2$gender) %>% 
  as.data.frame.matrix %>%
  mutate(node = row.names(.))

 > myTable
  neuter non.neuter rest     node
1      0          4    2    A-bom
2      3          0    2 acroniem
3      3          2    1      act
> str(myTable)
'data.frame':   3 obs. of  4 variables:
 $ neuter    : int  0 3 3
 $ non.neuter: int  4 0 2
 $ rest      : int  2 2 1
 $ node      : chr  "A-bom" "acroniem" "act"

# And here is a more understandable way if you are not familiar with piping
# To learn more about forward piping : https://github.com/smbache/magrittr 
myTable <- table(df2$node, df2$gender)
myTable2 <- as.data.frame.matrix(myTable)
myTable3 <- mutate(myTable2, node = row.names(myTable2))

【讨论】:

  • 这看起来很有希望。但是,我认为最好将 neuter、non.neuter 和 rest 放在一个名为 gender 的新列中。我不想覆盖precedingWord 中的值。不过,更重要的是,我不能将 df 列为一个整体,因为它包含更多列。在完成所有操作后克隆df,然后删除所有不需要的列,然后调用表函数会更好吗?
  • 另外,rest 的定义不应该引用中性和非中性变量本身,而不是字符串吗? IE。 ...c(neuter, non.neuter)] &lt;- "rest"?
  • 如果您更改为c(neuter, non.neuter) 而不是字符串,它将全部替换为rest,因为现在值等于“neuter”和“non.neuter”,所以!df$precedingWord %in% c(neuter, non.neuter) 将返回所有TRUE,因为“neuter”或“non.neuter”不是neuternon .neuter 对象中的值
  • 我的测试用例证明你错了。通过使用c(neuter, non.neuter),它将查看neuter &lt;- c("t", "het", "dat") non.neuter &lt;- c("de", "die") 内部,而不仅仅是字符串"neuter"、“non.neuter”。当我使用c("neuter", "non.neuter") 时,rest 总是正确的。使用c(neuter, non.neuter)时,不是。
  • 我想你不会直接用字符串替换“precedingWord”值。无论如何,我用一个可能更好的 dplyr 解决方案进行了编辑。
【解决方案2】:

R 通常不需要循环。它旨在使用向量和apply 命令作用于数据结构的所有元素。在这种情况下,您不需要使用tapply,因为table 函数已经完成了您想要的操作。

Julien 的答案适用于您的示例,但在(可能不寻常的)不存在给定类型的单词的情况下,它将失败。例如,如果您没有“neuter”字样,则表中将缺少“neuter”,而不是按预期显示全零。为了解决这个问题,您可以将单词类型视为一个因素。

请注意,在下面的代码中,我添加了第四种单词(“nonword”)来演示零单词的情况。

df<-as.data.frame(matrix(c("A-bom","de","A-bom","die","A-bom","de","A-bom","een","A-bom","n","A-bom","de","acroniem","het","acroniem","t","acroniem","het","acroniem","n","acroniem","een","act","de","act","het","act","die","act","dat","act","t","act","n"), byrow=T, ncol=2), stringsAsFactors=F)
names(df)<-c("node", "precedingWord")

# dictionary of word types. 
# I added a fourth type of word to demonstrate what happens 
# if no words of a given type are present.
classes<-c("t"="neuter", "het"="neuter" ,"dat"="neuter", "de"="non-neuter", "die"="non-neuter", "blorble"="nonword")

# create class variable and initialize to "rest"
df$class<-"rest"
df$class<-ifelse(!is.na(classes[df$precedingWord]), classes[df$precedingWord], "rest")

# note fourth category, "nonword", is missing.
table(df$node, df$class)

# make sure any missing categories are still possible levels for class
df$class<-factor(df$class)
levels(df$class)<-c(levels(df$class), unique(classes))

#now non-represented categories are still there. 
table(df$node, df$class)

【讨论】:

  • 我的数据集非常庞大,不可能没有某种类型的单词。但是,我确实会记住您的信息!
猜你喜欢
  • 1970-01-01
  • 2017-09-26
  • 2016-11-23
  • 2014-08-02
  • 2013-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-09
相关资源
最近更新 更多