示例数据
我在 R 中获得了以下调查数据集,并且需要有关特定新变量的条件计算的帮助。
# Load package
library(tidyverse)
# Important: set seed for replicability
set.seed(123)
# Create data: step 1
df <- tibble(
country = c(rep("A", 10), rep("B", 10)),
respondent_id = 1:20,
vote_choice = c(sample(c("PartyA", "PartyB", "PartyC"), 10, replace = TRUE),
sample(c("PartyD", "PartyE", "PartyF"), 10, replace = TRUE)),
ptv_1 = runif(20, min = 0, max = 1) %>% round(., 3),
ptv_2 = runif(20, min = 0, max = 1) %>% round(., 3),
ptv_3 = runif(20, min = 0, max = 1) %>% round(., 3)
)
# Create data: step 2
df <- df %>%
group_by(vote_choice, country) %>%
summarize(across(starts_with("ptv"), \(x) mean(x, na.rm = TRUE))) %>%
pivot_longer(cols = starts_with("ptv"), names_to = "party_to_ptv", values_to = "average_value") %>%
group_by(vote_choice, country) %>%
slice_max(order_by = average_value) %>%
ungroup() %>%
mutate(average_value = NULL) %>%
right_join(., df, by = c("vote_choice", "country"))
# Inspect data
df
# A tibble: 20 × 7
vote_choice country party_to_ptv respondent_id ptv_1 ptv_2 ptv_3
<chr> <chr> <chr> <int> <dbl> <dbl> <dbl>
1 PartyA A ptv_2 10 0.691 0.799 0.710
2 PartyB A ptv_3 4 0.544 0.233 0.810
3 PartyB A ptv_3 6 0.289 0.266 0.794
4 PartyB A ptv_3 7 0.147 0.858 0.440
5 PartyB A ptv_3 8 0.963 0.046 0.754
6 PartyC A ptv_1 1 0.994 0.369 0.274
7 PartyC A ptv_1 2 0.656 0.152 0.815
8 PartyC A ptv_1 3 0.709 0.139 0.449
9 PartyC A ptv_1 5 0.594 0.466 0.812
10 PartyC A ptv_1 9 0.902 0.442 0.629
11 PartyD B ptv_3 13 0.478 0.207 0.220
12 PartyD B ptv_3 16 0.318 0.895 0.352
13 PartyD B ptv_3 19 0.415 0.095 0.668
14 PartyD B ptv_3 20 0.414 0.384 0.418
15 PartyE B ptv_1 11 0.795 0.122 0.001
16 PartyE B ptv_1 12 0.025 0.561 0.475
17 PartyE B ptv_1 14 0.758 0.128 0.380
18 PartyF B ptv_2 15 0.216 0.753 0.613
19 PartyF B ptv_2 17 0.232 0.374 0.111
20 PartyF B ptv_2 18 0.143 0.665 0.244
变量信息:
country
在我的示例 df 中包含 2 个国家,每个国家包含 10 个受访者和受访者在上次选举中必须选择的一组 3 个不同政党(真实数据还包含一个变量 year
,我没有将其包含在内)为了简单起见)respondent_id
指的是调查数据集中的受访者,表明该数据集处于受访者级别,但可以忽略不计vote_choice
表示受访者在上次选举中投票支持的政党的名称ptv_1
、ptv_2
和ptv_3
表示每个可用政党的每个受访者对该政党的倾向(在真实数据中,受访者当然更倾向于他们投票支持的政党);规模:0-1
party_to_ptv
是一个转换列表,表示vote_choice
中的哪一方对应于哪ptv_*
列问题描述
我现在需要计算一组 (3) 个名为
electoral_opportunites_*
的新变量,其中星号是 1-3 的占位符,指的是三个 PTV。这个想法是根据其他政党选民的有利倾向来计算政党获得新选民的变化。
为此,我需要计算:
1 - (sqrt(PTV of party voted for) - sqrt(PTV of other party))
,其想法是设定自己政党相对于新政党的支持力度。例如,如果受访者通过 PTV = 1.0 强烈支持自己的政党 A,那么他们通过 PTV = 0.4 也倾向于 B 并不那么重要。
我的计算问题是条件性:我需要按行查找每个受访者与其选择方对应的 PTV 列值(可能不是行中最高的 PTV 值),然后从中减去平方-另一列的根值。
对于示例 df,我会手动执行以下操作。
预期结果(
electoral_opportunities_1
)
df %>%
mutate(electoral_potential_1 =
# Subtract: PTV (party voted for) - PTV (PTV column 1)...
c(1 - ( sqrt(0.799) - sqrt(0.691) ),
1 - ( sqrt(0.810) - sqrt(0.544) ),
1 - ( sqrt(0.794) - sqrt(0.289) ),
1 - ( sqrt(0.440) - sqrt(0.147) ),
1 - ( sqrt(0.754) - sqrt(0.963) ),
NA, # ...unless they are both the same.
NA,
NA,
NA,
NA,
1 - ( sqrt(0.220) - sqrt(0.478) ),
1 - ( sqrt(0.352) - sqrt(0.318) ),
1 - ( sqrt(0.668) - sqrt(0.415) ),
1 - ( sqrt(0.418) - sqrt(0.414) ),
NA,
NA,
NA,
1 - ( sqrt(0.753) - sqrt(0.216) ),
1 - ( sqrt(0.374) - sqrt(0.232) ),
1 - ( sqrt(0.665) - sqrt(0.143) )) ) -> df
df
作为一个小细节,我随后会检查是否有任何值 > 1 并将其上限为 1,这意味着如果受访者更强烈地倾向于他们实际上并未投票支持的政党,则该政党将获得最高分( 1) 在其选举变更方面以争取该选民。
df %>%
mutate(electoral_opportunities_1 = ifelse(electoral_opportunities_1 > 1, 1, electoral_opportunities_1)) -> df
我无法手工完成所有这些工作。因此,如果有一个高效、整洁的解决方案来计算各个 PTV 专栏的选举机会,我将不胜感激。我尝试了许多不同的方法,包括旋转 df,但到目前为止都没有奏效。综合起来,流程是:
编辑
我刚刚注意到,在最终的 df 中,我当然需要 vote_choice 中每个政党的平均选举机会,而不是三个单独的列!
这个解决方案看起来有点麻烦,但如果我正确理解你的问题,它应该可以工作:
library(tidyverse)
df %>%
pivot_longer(cols = starts_with("ptv"),
names_to = "ptv",
values_to = "ptv_value") %>%
group_by(respondent_id) %>%
mutate(voted_party_ptv = ptv_value[party_to_ptv == ptv]) %>%
ungroup() %>%
mutate(electoral_opportunity = ifelse(party_to_ptv != ptv,
pmin(1, 1 - (sqrt(voted_party_ptv) - sqrt(ptv_value))),
NA)) %>%
select(-c(voted_party_ptv, ptv_value)) %>%
pivot_wider(names_from = ptv,
values_from = electoral_opportunity,
names_prefix = "electoral_opportunity_") %>%
mutate(avg_electoral_opportunity = rowMeans(select(., starts_with("electoral_opportunity")), na.rm = TRUE))
给出:
vote_choice country party_to_ptv respondent_id electoral_opportunity_ptv_1 electoral_opportunity_ptv_2 electoral_opportunity_pt…¹ avg_e…²
<chr> <chr> <chr> <int> <dbl> <dbl> <dbl> <dbl>
1 PartyA A ptv_2 10 0.937 NA 0.949 0.943
2 PartyB A ptv_3 4 0.838 0.583 NA 0.710
3 PartyB A ptv_3 6 0.647 0.625 NA 0.636
4 PartyB A ptv_3 7 0.720 1 NA 0.860
5 PartyB A ptv_3 8 1 0.346 NA 0.673
6 PartyC A ptv_1 1 NA 0.610 0.526 0.568
7 PartyC A ptv_1 2 NA 0.580 1 0.790
8 PartyC A ptv_1 3 NA 0.531 0.828 0.679
9 PartyC A ptv_1 5 NA 0.912 1 0.956
10 PartyC A ptv_1 9 NA 0.715 0.843 0.779
11 PartyD B ptv_3 13 1 0.986 NA 0.993
12 PartyD B ptv_3 16 0.971 1 NA 0.985
13 PartyD B ptv_3 19 0.827 0.491 NA 0.659
14 PartyD B ptv_3 20 0.997 0.973 NA 0.985
15 PartyE B ptv_1 11 NA 0.458 0.140 0.299
16 PartyE B ptv_1 12 NA 1 1 1
17 PartyE B ptv_1 14 NA 0.487 0.746 0.616
18 PartyF B ptv_2 15 0.597 NA 0.915 0.756
19 PartyF B ptv_2 17 0.870 NA 0.722 0.796
20 PartyF B ptv_2 18 0.563 NA 0.678 0.621
您可以省略任何不需要的列
好吧,这显然比我最初想象的更直接。这是我为解决(80%)问题所做的工作。
df %>%
mutate(ptv_v = case_when(party_to_ptv == "ptv_1" ~ ptv_1,
party_to_ptv == "ptv_2" ~ ptv_2,
party_to_ptv == "ptv_3" ~ ptv_3,
T ~ NA_real_)) %>%
mutate(opportunity_1 = ifelse(ptv_1 > ptv_v, 1, 1 - (sqrt(ptv_v) - sqrt(ptv_1)) ) %>% ifelse(party_to_ptv == "ptv_1", NA, .)),
opportunity_1 = ifelse(party_to_ptv == "ptv_1") ) -> df
现在我只需要在 vote_choice 中获取每个政党的平均选举机会即可。 :)