切换行内的值

时间:2017-02-23 15:23:16

标签: r

我有一个包含几行的数据集。

x1  x2  x3  x4  x5  y1   y2   y3   y4   y5
1   3   2   1   5  0.2  0.1  0.1  0.4  0.2
1   2   4   2   4   -1   -1   -1   -1   -1
4   4   1   2   4  0.2  0.2  0.3  0.1  0.9

-1实际上只是一个任意值,表示没有东西。

我想将-1列中的y切换为x列:

x1  x2  x3  x4  x5  y1   y2   y3   y4   y5
 1   3   2   1   5  0.2  0.1  0.1  0.4  0.2
-1  -1  -1  -1  -1  1    2    4    2    4   ###Changed row
 4   4   1   2   4  0.2  0.2  0.3  0.1  0.9

这只是一个示例数据集;问题是,我有超过30个数据集,每个数据集都有1000多行数据,这些事情发生在几个地方。我知道有一种方法可以通过切断整个数据集和切换值来实现它,但我想知道是否有更优雅的方法来处理大型数据集,例如使用for循环?

4 个答案:

答案 0 :(得分:1)

另一种解决方案:

library(dplyr)

#Example dataframe
df <- data.frame(
  matrix(round(runif(15,min = 0,max=5),digits = 0),ncol = 5),
  matrix(round(runif(15,min = 0,max=1),digits = 1),ncol = 5,dimnames = list(NULL,paste0('y',1:5)))
)
df[2,6:10] <- -1

switcher_function <- function(d){
  d <- data.frame(t(d))
  df.y <- d %>% select(contains('y'))
  df.x <- d %>% select(contains('x'))
  if(sum(df.y)==-1*ncol(df.y)){
    return(as.numeric(cbind(df.y[1,],df.x[1,])))
  }else{
    return(as.numeric(cbind(df.x[1,],df.y[1,])))
  }
}

want <- t(apply(X = df,MARGIN = 1,FUN = switcher_function))

答案 1 :(得分:0)

这是一个使用基数R的想法,假设你只有2组不同的列(x和y),那么,

ind1 <- t(apply(df2, 1, function(i)mapply(function(x, y) 
           replace(x, all(y == -1), y), i[grepl('x', names(i))], i[grepl('y', names(i))])))

 ind2 <- t(apply(df2, 1, function(i)mapply(function(x, y) 
           replace(x, all(x == -1), y), i[grepl('y', names(i))], i[grepl('x', names(i))])))

final_df <- as.data.frame(cbind(ind1, ind2))

final_df
#   x1 x2 x3 x4 x5  y1  y2  y3  y4  y5
#1  1  3  2  1  5 0.2 0.1 0.1 0.4 0.2
#2 -1 -1 -1 -1 -1 1.0 2.0 4.0 2.0 4.0
#3  4  4  1  2  4 0.2 0.2 0.3 0.1 0.9

答案 2 :(得分:0)

In tidy data format,您的表格如下:

       i     x     y
1      1     1   0.2
2      1     1  -1.0
3      1     4   0.2
4      2     3   0.1
5      2     2  -1.0
6      2     4   0.2
7      3     2   0.1
8      3     4  -1.0
9      3     1   0.3
10     4     1   0.4
11     4     2  -1.0
12     4     2   0.1
13     5     5   0.2
14     5     4  -1.0
15     5     4   0.9

以这种格式给出,交换y为负的单元格是微不足道的(...):

mutate_when(df, y < 0, x = y, y = x)

这会将{dplyr>扩展名mutate_when)与its code available as a Github Gist一起使用。

或者你可以只使用来做同样的事情,但它有点复杂:

do(tibble(x = ifelse(.$y < 0, .$y, .$x),
          y = ifelse(.$y < 0, .$x, .$y),
          i = .$i))

这是使用同名包中的tibble中的do。可能有更好的方法 - 我只是不知道。

...但是让你的表格变得整洁,并且在转换之后,退出整洁的格式会有点复杂。这是整理数据的转变:

tidy_df = df %>%
    gather(name, value) %>%
    mutate(i = as.integer(sub('x|y', '', name)),
           name = sub('\\d', '', name)) %>%
    group_by(name, i) %>%
    mutate(row = row_number()) %>%
    ungroup() %>%
    spread(name, value)

(这会添加一个额外的列来保留原始表中的行索引,然后将其转换回来。如果不需要,那么索引也不会。)

现在我们可以执行交换......

tidy_df_swapped = tidy_df %>%
    mutate_when(y < 0, x = y, y = x)

之后转换回来看起来像这样:

df_swapped = tidy_df_swapped %>%
    gather(name, value, -i, -row) %>%
    mutate(name = paste0(name, i)) %>%
    select(-i) %>%
    spread(name, value) %>%
    select(-row)

答案 3 :(得分:0)

这是一个矩阵解决方案,因为它没有指定数据的存储方式。我还将-1更改为NA,因为它被声明是一个任意选择

m1 <- structure(c(1, 1, 4, 3, 2, 4, 2, 4, 1, 1, 2, 2, 5, 4, 4, 0.2, NA, 0.2, 0.1, NA, 0.2, 0.1, NA, 0.3, 0.4, 2, NA, 0.2, NA, NA),
                .Dim = c(3L, 10L),
                .Dimnames = list(NULL, c("x1", "x2", "x3", "x4", "x5", "y1", "y2", "y3", "y4", "y5")))

ind <- is.na(m1[, paste0("y", 1:5)])
m1[ind] <- c(tail(m1[ind], length(m1[ind])/2), head(m1[ind], length(m1[ind])/2))

提供一些速度比较(并节省微秒!)

Unit: microseconds
               min        lq      mean   median       uq       max neval
  matrix    47.940   64.8710   89.9407   86.939   98.734   165.126   100
final_df   704.258  742.3055  986.9160  791.767 1057.909  4310.011   100
    want  3647.605 3982.4225 5184.6407 4410.836 6450.177 15161.132   100

在第二步中可能有一种更优雅的方式来交换阵列,但它是我现在所拥有的。