R - 如果第2列中出现特定值,则从第1列中提取多行

时间:2018-01-25 08:53:54

标签: r dataframe rows

我有一个关于从R中的data.frame中提取多个值并将它们放入新的data.frame中的问题。

我有一个看起来像这样的数据框(df)

PRICE     EVENT
1.50        0
1.70        0
1.65        0
1.20        1
0.90        0
1.70        0
1.55        0 
  .         .
  .         .
1.10        0
1.20        0
1.14        1
0.90        0

我的实际data.frame有这两列和超过300.000行。名为EVENT的列仅具有值0 OR 1(值1是发生特定事件的代理)。

我的研究的第一步:如果事件发生,分析价格。 第一步很简单。我用

做到了
vector<-df[df$EVENT==1, "PRICE"]

现在vector包含活动日的所有价格。 (这里:1.20和1.14)

但是现在我研究的第二步是它变得有趣:

现在我不仅要求参加活动日的价格,还需要活动日前后x天的价格,并将它们放入矩阵

例如:我想要在活动前两天和活动后一天(包括活动日)的价格

比我想要创建的新data.frame看起来像

    Event 1               Event n
-2   1.70        ...        1.10
-1   1.65        ...        1.20
 0   1.20        ...        1.14
+1   0.90        ...        0.90

请记住,4天跨度[-2:1]只是一个例子。在我的实际研究中,我必须涵盖91天的跨度[-30:60]。

感谢您的帮助:)

4 个答案:

答案 0 :(得分:4)

我们可以创建一个包含相关行号的矩阵,然后将其用作掩码来达到预期的输出:

event_rows <- which(df$EVENT==1)
mask <- sapply(event_rows, function(x) (x-2):(x+2))
apply(mask, 2, function(x) df$PRICE[x])
#     [,1] [,2]
#[1,] 1.70 1.10
#[2,] 1.65 1.20
#[3,] 1.20 1.14
#[4,] 0.90 0.90
#[5,] 1.70   NA

数据

df <- structure(list(PRICE = c(1.5, 1.7, 1.65, 1.2, 0.9, 1.7, 1.55, 
1.1, 1.2, 1.14, 0.9), EVENT = c(0L, 0L, 0L, 1L, 0L, 0L, 0L, 0L, 
0L, 1L, 0L)), .Names = c("PRICE", "EVENT"), class = "data.frame", row.names = c(NA, 
-11L))

答案 1 :(得分:2)

为了完成,这里有一个基础R解决方案:

# example data
set.seed(123)
df <- data.frame(price = rnorm(100), event = rbinom(100, 1, 0.05))

# create a vector of unique event positions with additional 2 positions before and 1 ahead
offset <- unique(as.vector(sapply(which(df$event == 1), function(x) c((x-2):(x+1)))))

# subset data    
df[offset[offset >0 & offset <= 100],]


         price event
1  -0.56047565     0
2  -0.23017749     1
3   1.55870831     0
20 -0.47279141     0
21 -1.06782371     0
22 -0.21797491     1
23 -1.02600445     0
46 -1.12310858     0
47 -0.40288484     0
48 -0.46665535     1
49  0.77996512     1
50 -0.08336907     0
62 -0.50232345     0
63 -0.33320738     0
64 -1.01857538     1
65 -1.07179123     0
75 -0.68800862     0
76  1.02557137     0
77 -0.28477301     1
78 -1.22071771     0
95  1.36065245     0
96 -0.60025959     0
97  2.18733299     1
98  1.53261063     0

编辑:我最初没有看到预期的输出,请参阅@ mtoto的答案。

答案 2 :(得分:0)

我要做的是,用滞后扩展基础数据数据框,然后按行选择。使用tidyverse就可以这样了。 (我强烈建议使用tidyverse而不是基础R.但这取决于你)

library(tidyverse)

# generate example data frame

df <- data.frame(price = rnorm(100), event = rbinom(100, 1, 0.5))

# generate a vector from one the desired number of lags.
# we map this vector with a function that returns the lagged
# values of the price. then we join by columns
lags <- map(1:3, function(x){lag(df$price, n = x)}) %>%
    reduce(cbind) %>% as.data.frame %>% 
    set_names(paste('priceLag', 1:3, sep = ''))

# bind lags to original data frame, select events == 1
out <- cbind(df, lags) %>% filter(df$event == 1)

答案 3 :(得分:0)

library('tidyverse')


df <- data.frame(
  price = seq_len(20),
  event = c(0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0))
df
#    price event
# 1      1     0
# 2      2     0
# 3      3     0
# 4      4     0
# 5      5     1
# 6      6     0
# 7      7     0
# 8      8     0
# 9      9     0
# 10    10     0
# 11    11     0
# 12    12     1
# 13    13     0
# 14    14     0
# 15    15     0
# 16    16     1
# 17    17     1
# 18    18     0
# 19    19     0
# 20    20     0

您可以使用laglead来获取偏移值。然后使用gatherspread的组合将数据框翻转为所需的形状。

df %>%
  mutate(
    `-2` = lag(price, 2),
    `-1` = lag(price),
    `0` = price,
    `+1` = lead(price)) %>%
  select(-price) %>%
  filter(event == 1) %>%
  mutate(event = paste0('event_', seq_along(event))) %>%
  gather('offset', 'value', -event) %>%
  spread(event, value) %>%
  arrange(as.numeric(offset))
#   offset event_1 event_2 event_3 event_4
# 1     -2       3      10      14      15
# 2     -1       4      11      15      16
# 3      0       5      12      16      17
# 4     +1       6      13      17      18