3

我有一个数据框,其中每一行代表每个人的交互数据。

actions = read.table('C:/Users/Desktop/actions.csv', header = F, sep = ',', na.strings = '', stringsAsFactors = F)

每个人都可以有以下一种或多种互动:

eat, sleep, walk, jump, hop, wake, run

为每个人记录的动作长度可能会有所不同,如下所示:

P1: eat,  sleep, sleep, sleep
P2: wake, walk,  eat,   walk, walk, jump, jump, run, run
P3: wake, eat,   walk,  jump, run,  sleep

为了使长度相等,我在最后有 NA 填充:

P1: eat,  sleep, sleep, sleep, NA,   NA,    NA,   NA,  NA
P2: wake, walk,  eat,   walk,  walk, jump,  jump, run, run
P3: wake, eat,   walk,  jump,  run,  sleep, NA,   NA,  NA

现在,我的要求是更新每个人的条目(按行数据),以便没有两个连续的条目是重复的。维持秩序非常重要。我需要的输出是:

P1: eat,  sleep, NA,   NA,   NA,   NA,    NA,   NA,  NA
P2: wake, walk,  eat,  walk, jump, run,   NA,   NA,  NA 
P3: wake, eat,   walk, jump, run,  sleep, NA,   NA,  NA

列名默认为 V1、V2、V3 .... Vn 其中

n = maximum length of interactions string 

在上面的例子中,P2 有最大长度;所以 n = 9。所以上例中的总列来自 V1-V9。

的输出

dput(actions)

structure(list(V1 = c("S", "C", "R"), V2 = c("C", "C", "R"), 
V3 = c("R", "C", "R"), V4 = c("S", NA, "R"), V5 = c("C", 
NA, "R"), V6 = c("R", NA, NA), V7 = c("S", NA, NA), V8 = c("C", 
NA, NA), V9 = c("R", NA, NA)), class = "data.frame", row.names = c(NA,-3L))

以下问题:Removing Only Adjacent Duplicates in Data Frame in R与我的有点相似,但是有几个不同之处。即使合并上述问题中的代码,我也无法解决我的问题。

对此的任何建议将不胜感激!

4

3 回答 3

3
library(tidyverse)

read.csv(text=gsub(" +", "", "P1, eat,  sleep, sleep, sleep, NA,   NA,    NA,   NA,  NA
P2, wake, walk,  eat,   walk,  walk, jump,  jump, run, run
P3, wake, eat,   walk,  jump,  run,  sleep, NA,   NA,  NA"), 
           header = FALSE, stringsAsFactors = FALSE) %>% 
  setNames(c("person", sprintf("i%s", 1:9))) %>% tbl_df() -> xdf

de_dup <- function(x) {
  # remove consecutive dups and keep order
  interactions <- rle(unlist(x, use.names = FALSE)[-1])$values
  # fill in NAs
  interactions <- c(interactions, rep(NA_character_, length(x[-1])-length(interactions)))
  # return a data frame
  as.data.frame(as.list(setNames(c(x[1], interactions), names(x))), stringsAsFactors=FALSE)
}

rowwise(xdf) %>% 
  do(de_dup(.)) %>% 
  ungroup()
## # A tibble: 3 x 10
##   person i1    i2    i3    i4    i5    i6    i7    i8    i9   
## * <chr>  <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr> <chr>
## 1 P1     eat   sleep NA    NA    NA    NA    NA    NA    NA   
## 2 P2     wake  walk  eat   walk  jump  run   NA    NA    NA   
## 3 P3     wake  eat   walk  jump  run   sleep NA    NA    NA 

要求的博览会

由于 dup 是跨列的,因此最直接的方法(不一定是最快或最少的内存/CPU 密集型)是逐行重新创建数据帧。

  • rowwise()是一个tidyverse按行将数据框分成组的函数
  • 然后,我们获取每一行(使用do())并将其传递给我们创建的函数,以使代码更具可读性和可更新性(不像{}用分号和换行符混淆内联括号的疯狂)。==整.
  • x参数 in将de_dup()是一个命名列表(阅读文档do
  • 我们把这个列表变成一个向量unlist()
  • 然后我们将它传递给rle函数,而不是第一个元素,即人。这不是完全必要的(这个人将是独一无二的),但它具有注意逻辑,因为您知道您正在处理与人的交互。查看 的输出rle(c("a", "a", "b", "c", "c", "c", "d))以了解它的作用。它代表运行长度编码,专为满足您的需求而设计
  • 的返回值rle具有一个values元素,该元素具有不带 s 的去重元素NA
  • 由于^^,我们必须再次重新填充NAs。很多方法可以做到这一点。我喜欢这种方式。
  • 然后我们必须返回一个数据框(do()再次检查文档),因此我们创建一个命名字符向量并将其转换为数据框
  • 最后do()我们仍然有一个逐行分组的数据框,所以我们需要取消分组
于 2018-11-10T11:55:46.437 回答
1

和基础 R的组合。首先dplyrreshape2它识别所需的重复项并将它们替换为 NA。然后,它将非 NA 值向左移动。

as.data.frame(t(apply(df %>%
          gather(var, val, -V1) %>% 
          group_by(V1) %>% 
          mutate(val2 = ifelse(val == lag(val), NA, val),
                 val2 = ifelse(var == "V2", paste(val), val2)) %>% 
          dcast(V1~var, value.var = "val2"), 1, function(x) c(x[!is.na(x)], x[is.na(x)]))))

  V1   V2    V3   V4   V5   V6    V7   V8   V9  V10
1 P1  eat sleep <NA> <NA> <NA>  <NA> <NA> <NA> <NA>
2 P2 wake  walk  eat walk jump   run <NA> <NA> <NA>
3 P3 wake   eat walk jump  run sleep <NA> <NA> <NA>

数据(使用来自@Shree 的代码):

df <- read.csv(text = gsub(" +", "", "P1, eat,  sleep, sleep, sleep, NA,   NA,    NA,   NA,  NA
            P2, wake, walk,  eat,   walk,  walk, jump,  jump, run, run
            P3, wake, eat,   walk,  jump,  run,  sleep, NA,   NA,  NA"), 
               header = FALSE, stringsAsFactors = FALSE)
于 2018-11-10T22:16:01.213 回答
1

这是使用基础 R 的一种简单方法。我只是创建了一个函数,该函数将替换连续的重复项NA并按所需顺序重新排列新行 -

# function to check consecutive duplicates
ccd <- function(x) {
  # first value can never be duplicate so initiating to 0
  test <- c(0, sapply(1:(length(x)-1), function(i) anyDuplicated(x[i:(i+1)])))
  x[test > 0] <- NA_character_
  x[order(test)]
}

# Original df from dput
> df
  V1 V2 V3   V4   V5   V6   V7   V8   V9
1  S  C  R    S    C    R    S    C    R
2  C  C  C <NA> <NA> <NA> <NA> <NA> <NA>
3  R  R  R    R    R <NA> <NA> <NA> <NA>

for(r in 1:nrow(df)) {
  df[r, ] <- ccd(as.character(df[r, ]))
}

> df
  V1   V2   V3   V4   V5   V6   V7   V8   V9
1  S    C    R    S    C    R    S    C    R
2  C <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>
3  R <NA> <NA> <NA> <NA> <NA> <NA> <NA> <NA>

对于帖子中的演示示例 -

df <- read.csv(
text=gsub(" +", "", "P1, eat,  sleep, sleep, sleep, NA,   NA,    NA,   NA,  NA
P2, wake, walk,  eat,   walk,  walk, jump,  jump, run, run
                         P3, wake, eat,   walk,  jump,  run,  sleep, NA,   NA,  NA"), 
               header = FALSE, stringsAsFactors = FALSE)[, -1]

> df
    V2    V3    V4    V5   V6    V7   V8   V9  V10
1  eat sleep sleep sleep <NA>  <NA> <NA> <NA> <NA>
2 wake  walk   eat  walk walk  jump jump  run  run
3 wake   eat  walk  jump  run sleep <NA> <NA> <NA>

for(r in 1:nrow(df)) {
  df[r, ] <- ccd(as.character(df[r, ]))
}

> df
    V2    V3   V4   V5   V6    V7   V8   V9  V10
1  eat sleep <NA> <NA> <NA>  <NA> <NA> <NA> <NA>
2 wake  walk  eat walk jump   run <NA> <NA> <NA>
3 wake   eat walk jump  run sleep <NA> <NA> <NA>
于 2018-11-10T13:15:41.763 回答