【问题标题】:How do I create many variables, that depend on multiple conditions in R (akin to the array-function in SAS)如何创建许多变量,这些变量取决于 R 中的多个条件(类似于 SAS 中的数组函数)
【发布时间】:2021-06-14 04:33:43
【问题描述】:

我正在分析一个时间使用数据集,其中对于每个家庭成员,144 列表示他们在每 10 分钟时段(即从 08:00 到 08:10)进行的活动,144 列表示,如果合作伙伴在每个间隔都在场,依此类推。

我正在尝试创建两种不同类型的变量。

  1. 我需要总结一个人在有和没有伴侣的情况下在某些活动中所花费的时间(例如,一个用于谈话和吃饭的总和变量,一个用于休闲的总和变量)。

在 SAS 中,这与使用这样的数组一起工作:

array main_men(*) main_men_1-main_men_144;
array partner_men(*) partner_men_1-partner_men_144;

sum_eating = 0;
do i=1 to 144; if main_men(i) in (100:200) & partner_men(i) in (0) 
then sum_eating = sum_eating + 10; end;

因此,特定活动代码的每次出现和伙伴在同一个变量槽(1 到 144)中的条件都满足,一个新变量增加了 +10 分钟(因为每次出现代表一个 10 分钟时隙。 在 R 中,count 满足这两个条件的次数就足够了。

  1. 为了进行序列分析,我不仅需要总和变量,还需要 144 个新变量,这些变量表明个人是独自休闲还是与伴侣一起休闲,还是在做无偿工作等。

所以我需要 144 个变量来代替 24 个变量。 再说一次,我只知道 SAS 逻辑,但我想完全放弃 SAS 并转向 R。

array seq(*) seq_1-seq_144;

do i=1 to 144; if main_men(i) in (200:399) and partner_men(i) in (0) 
then seq_paar(i)=1; end; 

do i=1 to 144; if main_men(i) in (200:399) and partner_men(i) in (1) 
then seq_paar(i)=2; end; 

在这里,我创建了 144 个空白变量,如果特定活动代码发生并且个人独自一人(partner_men 为 0)则为 1,如果代码发生但个人与伴侣在一起则为 0。

我创建了一个数据集的小样本,希望它更加清晰和可重复:

structure(list(id = c(11, 12, 17, 31, 35, 36, 41, 42, 47, 61), 
    men_main_55 = c(210, 210, 421, 992, 132, 622, 630, 466, 611, 
    969), men_main_56 = c(210, 210, 421, 992, 132, 622, 630, 
    466, 611, 969), men_main_57 = c(210, 210, 421, 992, 611, 
    622, 630, 466, 611, 969), men_main_58 = c(210, 210, 421, 
    131, 120, 622, 466, 466, 611, 641), men_main_59 = c(210, 
    210, 421, 452, 120, 622, 466, 466, 611, 641), men_main_60 = c(210, 
    210, 421, 452, 120, 622, 466, 466, 611, 641), wom_main_55 = c(210, 
    210, 421, 992, 411, 622, 421, 120, 641, 630), wom_main_56 = c(210, 
    210, 421, 992, 411, 622, 947, 120, 641, 630), wom_main_57 = c(210, 
    210, 421, 992, 611, 622, 947, 120, 641, 630), wom_main_58 = c(210, 
    210, 421, 998, 120, 622, 947, 421, 641, 630), wom_main_59 = c(210, 
    210, 421, 461, 120, 622, 421, 421, 641, 630), wom_main_60 = c(210, 
    210, 421, 461, 120, 622, 421, 421, 641, 630), partner_men_55 = c(0, 
    0, 1, 1, 0, 1, 0, 0, 1, 0), partner_men_56 = c(0, 0, 1, 1, 
    0, 1, 0, 0, 1, 0), partner_men_57 = c(0, 0, 1, 1, 1, 1, 0, 
    0, 1, 0), partner_men_58 = c(0, 0, 1, 0, 1, 1, 0, 0, 1, 1
    ), partner_men_59 = c(0, 0, 1, 0, 1, 1, 0, 0, 1, 1), partner_men_60 = c(0, 
    0, 1, 0, 1, 1, 0, 0, 1, 1), partner_wom_55 = c(0, 0, 1, 1, 
    0, 1, 0, 0, 1, 0), partner_wom_56 = c(0, 0, 1, 1, 0, 1, 0, 
    0, 1, 0), partner_wom_57 = c(0, 0, 1, 1, 1, 1, 0, 0, 1, 0
    ), partner_wom_58 = c(0, 0, 1, 0, 1, 1, 0, 0, 1, 0), partner_wom_59 = c(0, 
    0, 1, 0, 1, 1, 0, 0, 1, 0), partner_wom_60 = c(0, 0, 1, 0, 
    1, 1, 0, 0, 1, 0)), row.names = c(NA, -10L), label = "PAARZEIT_SEQ", 
class = c("tbl_df", "tbl", "data.frame"))

任何帮助将不胜感激。我尝试了各种 applyloop 方法,但没有任何效果。 谢谢!

【问题讨论】:

  • 您可以添加您的预期输出吗?你也没有定义sum_eating
  • 你说得对,我忘了定义 sum_eating 变量。
  • 我对第 1 部分的预期输出)将是每个人的变量,其中包含满足此条件的出现次数。对于第 2 部分)我需要从 1 到 144 的 144 个变量,指示个人在相应的 main_x 变量中是否有特定的活动代码,并且在相应的 partner_men 变量中是否有 0。

标签: r loops


【解决方案1】:

您的示例数据与您的示例代码不一致(检查列名)并且您没有给我们任何预期的输出,因此很难确定您到底想要什么。

SAS 和 R 对数据集/数据帧的看法的根本区别在于 SAS 将数据视为 的集合,而 R 将数据视为 列:他们的世界观是相互垂直的。因此,只需将您的 SAS 代码翻译成 R 语言,您就很难过自己的生活。在你的第二个问题中,困难尤其明显。如果您在从 SAS 迁移到 R 时将世界观从行转移到列,从长远来看,您将为自己省去很多痛苦和努力。

[顺便说一句,在一个帖子上问两个问题是不好的形式。]

采用tidy 数据实践也将是有益的,无论您是在 SAS 还是 R 中工作:原则是通用的。

也就是说,回答你的第一个问题:

library(tidyverse)

df %>% 
  rowwise() %>% 
  mutate(
    sumEatingMen=10*rowSums(across(starts_with("men_main_"), ~. %in% 100:200)),
    sumEatingWom=10*rowSums(across(starts_with("wom_main_"), ~. %in% 100:200))
  ) %>% 
  ungroup() %>% 
  select(id, sumEatingMen, sumEatingWom)
# A tibble: 10 x 3
      id sumEatingMen sumEatingWom
   <dbl>        <dbl>        <dbl>
 1    11            0            0
 2    12            0            0
 3    17            0            0
 4    31           10            0
 5    35           50           30
 6    36            0            0
 7    41            0            0
 8    42            0           30
 9    47            0            0
10    61            0            0

要以类似 R 的方式回答问题,首先将数据转换为整洁的格式:

df1a <- df %>% 
  pivot_longer(
    cols=c(starts_with("men"), starts_with("wom")),
    names_pattern="(.*)_main_(.*)",
    values_to="Activity",
    names_to=c("Sex", "Index")
  ) %>% 
  select(id, Sex, Index, Activity)
df1b <- df %>% 
  pivot_longer(
    cols=c(starts_with("partner")),
    names_pattern="partner_(.*)_(.*)",
    values_to="Partner",
    names_to=c("Sex", "Index")
  ) %>% 
  select(id, Sex, Index, Partner)
df1 <- df1a %>% full_join(df1b, by=c("id", "Sex", "Index"))
df1
# A tibble: 120 x 5
      id Sex   Index Activity Partner
   <dbl> <chr> <chr>    <dbl>   <dbl>
 1    11 men   55         210       0
 2    11 men   56         210       0
 3    11 men   57         210       0
 4    11 men   58         210       0
 5    11 men   59         210       0
 6    11 men   60         210       0
 7    11 wom   55         210       0
 8    11 wom   56         210       0
 9    11 wom   57         210       0
10    11 wom   58         210       0
# … with 110 more rows

你的问题的答案是那么

df1 %>% 
   group_by(id, Sex) %>% 
   summarise(sumEating=10*sum(Activity %in% 100:200), .groups="drop")
# A tibble: 20 x 3
      id Sex   sumEating
 * <dbl> <chr>     <dbl>
 1    11 men           0
 2    11 wom           0
 3    12 men           0
 4    12 wom           0
 5    17 men           0
 6    17 wom           0
 7    31 men          10
 8    31 wom           0
 9    35 men          50
10    35 wom          30
<10 rows omitted>

请注意,与类似 SAS 的解决方案相比,此解决方案更通用、更紧凑和更易读。

以简洁的方式回答您的第二个问题:

df1 %>%
  mutate(unpaidWorkWithPartner=Activity %in% 200:399 & Partner == 1)
# A tibble: 120 x 6
      id Sex   Index Activity Partner unpaidWorkWithPartner
   <dbl> <chr> <chr>    <dbl>   <dbl> <lgl>                
 1    11 men   55         210       0 FALSE                
 2    11 men   56         210       0 FALSE                
 3    11 men   57         210       0 FALSE                
 4    11 men   58         210       0 FALSE                
 5    11 men   59         210       0 FALSE                
 6    11 men   60         210       0 FALSE                
 7    11 wom   55         210       0 FALSE                
 8    11 wom   56         210       0 FALSE                
 9    11 wom   57         210       0 FALSE                
10    11 wom   58         210       0 FALSE                
# … with 110 more rows

如果我正确理解了您的帖子,那么在您的示例数据集中,没有人在任何时候与他们的合作伙伴进行任何无偿工作。

可以以类似 SAS 的方式回答您的第二个问题,但我怀疑该解决方案会冗长、脆弱且笨拙。我当然没有时间进一步调查。

【讨论】:

  • 非常感谢您的宝贵时间和回答!我意识到我在提出问题和提供明确的预期输出时并不太精确。我正在尝试从 SAS 迁移到 R,所以我一直在寻找整洁的方法,感谢您的见解!这两种方法都完美无缺。
猜你喜欢
  • 2022-12-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-17
  • 2022-12-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多