按列值将数学计算应用于 DF 的所有行
Apply Math calculation to all rows of DF by Column Values
我想应用一个数学计算 (Occ_1+1)/(Totl_1+Unique_words)
, (Occ_2+1)/(Totl_2+Unique_words)
和 (Occ_3+1)/(Totl_3+Unique_words)
并创建一个新列作为 Probability_1
, Probability_2
, Probability_3
现在我正在分别进行每项计算并将它们组合在一起。
例如:(Occ_1+1)
我正在做 sapply(df$Occ_1, function(x){x+1})
。
我几乎有 50 Occ_
和 50 Totl_
,所以如果我单独进行所有计算,我的代码会变得很长。
有没有办法一次完成所有计算。
样本 DF 直到 Occ_3
和 Totl_3
仅
word Occ_1 Occ_2 Occ_3 Totl_1 Totl_2 Totl_3 Unique_words
<chr> <int> <int> <int> <int> <int> <int> <int>
1 car 0 1 0 11 9 7 17
2 saturn 2 0 2 11 9 7 17
3 survival 1 2 0 11 9 7 17
4 baseball 1 1 0 11 9 7 17
5 color 0 0 1 11 9 7 17
6 muscle 0 1 0 11 9 7 17
这实际上就是所谓的函数矢量化,它可以显着提高代码的性能。
但首先,为了让您了解以后的问题,使用 dput
提供示例数据要容易得多
dput(df)
那么想回答问题的人可以简单地使用输出:
df <- dget(structure(list(word = structure(c(2L, 5L, 6L, 1L, 3L, 4L), .Label = c("baseball",
"car", "color", "muscle", "saturn", "survival"), class = "factor"),
Occ_1 = c(0L, 2L, 1L, 1L, 0L, 0L), Occ_2 = c(1L, 0L, 2L,
1L, 0L, 1L), Occ_3 = c(0L, 2L, 0L, 0L, 1L, 0L), Totl_1 = c(11L,
11L, 11L, 11L, 11L, 11L), Totl_2 = c(9L, 9L, 9L, 9L, 9L,
9L), Totl_3 = c(7L, 7L, 7L, 7L, 7L, 7L), Unique_words = c(17L,
17L, 17L, 17L, 17L, 17L), Probability_1 = c(0.0357142857142857,
0.107142857142857, 0.0714285714285714, 0.0714285714285714,
0.0357142857142857, 0.0357142857142857), Probability_2 = c(0.0769230769230769,
0.0384615384615385, 0.115384615384615, 0.0769230769230769,
0.0384615384615385, 0.0769230769230769), Probability_3 = c(0.0416666666666667,
0.125, 0.0416666666666667, 0.0416666666666667, 0.0833333333333333,
0.0416666666666667)), row.names = c(NA, -6L), class = "data.frame"))
无论如何,这里有一个方法可以做你想做的事:
df$Probability_1 <- (df$Occ_1 + 1) / (df$Totl_1 + df$Unique_words)
df$Probability_2 <- (df$Occ_2 + 1) / (df$Totl_2 + df$Unique_words)
df$Probability_3 <- (df$Occ_3 + 1) / (df$Totl_3 + df$Unique_words)
或者如果你喜欢 dplyr
:
library("dplyr")
df_new <- df %>%
mutate(
Probability_1 = (Occ_1 + 1) / (Totl_1 + Unique_words),
Probability_2 = (Occ_2 + 1) / (Totl_2 + Unique_words),
Probability_3 = (Occ_3 + 1) / (Totl_3 + Unique_words)
)
更新
我错过了问题的重点。它实际上是关于 Occ
和 Totl
变量的数量。我会用 for 循环来解决这个问题,它应该仍然非常有效:
for(i in gsub("^Occ_", "", grep("^Occ_*", colnames(df), value = TRUE))) {
df[paste0("Probability_", i)] <-
(df[paste0("Occ_", i)] + 1) / (df[paste0("Totl_", i)] + df$Unique_words)
}
我只是将所有 Occ..
、 Tot..
列聚集在一起并执行所需的算法
occ_cols <- grep("^Occ", names(df))
tot_cols <- grep("^Totl", names(df))
df[paste0("Probability_", 1:length(occ_cols))] <-
(df[occ_cols] + 1)/(df[tot_cols] + df$Unique_words)
df
# word Occ_1 Occ_2 Occ_3 Totl_1 Totl_2 Totl_3 Unique_words Probability_1
#1 car 0 1 0 11 9 7 17 0.03571429
#2 saturn 2 0 2 11 9 7 17 0.10714286
#3 survival 1 2 0 11 9 7 17 0.07142857
#4 baseball 1 1 0 11 9 7 17 0.07142857
#5 color 0 0 1 11 9 7 17 0.03571429
#6 muscle 0 1 0 11 9 7 17 0.03571429
# Probability_2 Probability_3
#1 0.07692308 0.04166667
#2 0.03846154 0.12500000
#3 0.11538462 0.04166667
#4 0.07692308 0.04166667
#5 0.03846154 0.08333333
#6 0.07692308 0.04166667
但是,请确保所有 Occ..
和 Tot..
列的顺序相同。对于此示例,我们有 Occ_1
、Occ_2
、Occ_3
,然后是 Totl_1
、Totl_2
和 Totl_3
。
我将提出与其他两个答案不同的方法。我认为你在这里使用了错误的数据格式,即你的数据在应该很长的时候很宽。如果您不熟悉这些术语,您应该查看网上的大量解释。在我看来,最好的是 this one.
使用 tidyr
包,我会这样解决你的问题:
library(tidyverse)
第一步是将 Occ 和 Totl 列分成 2 个数据框,稍后我们将它们合并在一起。使用 gather
函数,我将这些列转换为键值对。我们正在从键中提取数值,以便稍后可以将 Occ_1 匹配到 Totl_1。
df_occ <- df %>%
gather(group, occ, contains("Occ")) %>%
select(word, group, occ) %>%
mutate(group = str_extract(group, "[0-9]") %>% as.integer())
df_totl <- df %>%
gather(group, totl, contains("Totl")) %>%
select(word, group, totl) %>%
mutate(group = str_extract(group, "[0-9]") %>% as.integer())
一旦我们有了这两个数据框,我们就会将它们重新合并在一起。我们从原始数据框中取出 word
和 Unique_words
列,然后按组添加 Occ 数据框,最后添加 Totl 数据框。终于,我们一行代码就可以完成你想要的计算了。
df_merge <- df %>%
select(word, Unique_words) %>%
left_join(df_occ, by = 'word') %>%
left_join(df_totl, by = c('word', 'group')) %>%
mutate(prob = (occ + 1) / (totl + Unique_words))
如果要将其转换回宽格式,可以使用 gather
函数的反函数,即 spread
.
df_wide <- df_merge %>%
select(word, group, prob) %>%
mutate(group = paste0("Prob_", group)) %>%
spread(group, prob)
这种方法的优点:
- 您的代码更易读,每个操作都在自己的行中,并且避免了方括号(这通常会产生难以阅读的代码)。
- 您的代码显示了中间步骤。
- 该方法更加灵活,希望也能简化其他处理步骤。
我想应用一个数学计算 (Occ_1+1)/(Totl_1+Unique_words)
, (Occ_2+1)/(Totl_2+Unique_words)
和 (Occ_3+1)/(Totl_3+Unique_words)
并创建一个新列作为 Probability_1
, Probability_2
, Probability_3
现在我正在分别进行每项计算并将它们组合在一起。
例如:(Occ_1+1)
我正在做 sapply(df$Occ_1, function(x){x+1})
。
我几乎有 50 Occ_
和 50 Totl_
,所以如果我单独进行所有计算,我的代码会变得很长。
有没有办法一次完成所有计算。
样本 DF 直到 Occ_3
和 Totl_3
仅
word Occ_1 Occ_2 Occ_3 Totl_1 Totl_2 Totl_3 Unique_words
<chr> <int> <int> <int> <int> <int> <int> <int>
1 car 0 1 0 11 9 7 17
2 saturn 2 0 2 11 9 7 17
3 survival 1 2 0 11 9 7 17
4 baseball 1 1 0 11 9 7 17
5 color 0 0 1 11 9 7 17
6 muscle 0 1 0 11 9 7 17
这实际上就是所谓的函数矢量化,它可以显着提高代码的性能。
但首先,为了让您了解以后的问题,使用 dput
dput(df)
那么想回答问题的人可以简单地使用输出:
df <- dget(structure(list(word = structure(c(2L, 5L, 6L, 1L, 3L, 4L), .Label = c("baseball",
"car", "color", "muscle", "saturn", "survival"), class = "factor"),
Occ_1 = c(0L, 2L, 1L, 1L, 0L, 0L), Occ_2 = c(1L, 0L, 2L,
1L, 0L, 1L), Occ_3 = c(0L, 2L, 0L, 0L, 1L, 0L), Totl_1 = c(11L,
11L, 11L, 11L, 11L, 11L), Totl_2 = c(9L, 9L, 9L, 9L, 9L,
9L), Totl_3 = c(7L, 7L, 7L, 7L, 7L, 7L), Unique_words = c(17L,
17L, 17L, 17L, 17L, 17L), Probability_1 = c(0.0357142857142857,
0.107142857142857, 0.0714285714285714, 0.0714285714285714,
0.0357142857142857, 0.0357142857142857), Probability_2 = c(0.0769230769230769,
0.0384615384615385, 0.115384615384615, 0.0769230769230769,
0.0384615384615385, 0.0769230769230769), Probability_3 = c(0.0416666666666667,
0.125, 0.0416666666666667, 0.0416666666666667, 0.0833333333333333,
0.0416666666666667)), row.names = c(NA, -6L), class = "data.frame"))
无论如何,这里有一个方法可以做你想做的事:
df$Probability_1 <- (df$Occ_1 + 1) / (df$Totl_1 + df$Unique_words)
df$Probability_2 <- (df$Occ_2 + 1) / (df$Totl_2 + df$Unique_words)
df$Probability_3 <- (df$Occ_3 + 1) / (df$Totl_3 + df$Unique_words)
或者如果你喜欢 dplyr
:
library("dplyr")
df_new <- df %>%
mutate(
Probability_1 = (Occ_1 + 1) / (Totl_1 + Unique_words),
Probability_2 = (Occ_2 + 1) / (Totl_2 + Unique_words),
Probability_3 = (Occ_3 + 1) / (Totl_3 + Unique_words)
)
更新
我错过了问题的重点。它实际上是关于 Occ
和 Totl
变量的数量。我会用 for 循环来解决这个问题,它应该仍然非常有效:
for(i in gsub("^Occ_", "", grep("^Occ_*", colnames(df), value = TRUE))) {
df[paste0("Probability_", i)] <-
(df[paste0("Occ_", i)] + 1) / (df[paste0("Totl_", i)] + df$Unique_words)
}
我只是将所有 Occ..
、 Tot..
列聚集在一起并执行所需的算法
occ_cols <- grep("^Occ", names(df))
tot_cols <- grep("^Totl", names(df))
df[paste0("Probability_", 1:length(occ_cols))] <-
(df[occ_cols] + 1)/(df[tot_cols] + df$Unique_words)
df
# word Occ_1 Occ_2 Occ_3 Totl_1 Totl_2 Totl_3 Unique_words Probability_1
#1 car 0 1 0 11 9 7 17 0.03571429
#2 saturn 2 0 2 11 9 7 17 0.10714286
#3 survival 1 2 0 11 9 7 17 0.07142857
#4 baseball 1 1 0 11 9 7 17 0.07142857
#5 color 0 0 1 11 9 7 17 0.03571429
#6 muscle 0 1 0 11 9 7 17 0.03571429
# Probability_2 Probability_3
#1 0.07692308 0.04166667
#2 0.03846154 0.12500000
#3 0.11538462 0.04166667
#4 0.07692308 0.04166667
#5 0.03846154 0.08333333
#6 0.07692308 0.04166667
但是,请确保所有 Occ..
和 Tot..
列的顺序相同。对于此示例,我们有 Occ_1
、Occ_2
、Occ_3
,然后是 Totl_1
、Totl_2
和 Totl_3
。
我将提出与其他两个答案不同的方法。我认为你在这里使用了错误的数据格式,即你的数据在应该很长的时候很宽。如果您不熟悉这些术语,您应该查看网上的大量解释。在我看来,最好的是 this one.
使用 tidyr
包,我会这样解决你的问题:
library(tidyverse)
第一步是将 Occ 和 Totl 列分成 2 个数据框,稍后我们将它们合并在一起。使用 gather
函数,我将这些列转换为键值对。我们正在从键中提取数值,以便稍后可以将 Occ_1 匹配到 Totl_1。
df_occ <- df %>%
gather(group, occ, contains("Occ")) %>%
select(word, group, occ) %>%
mutate(group = str_extract(group, "[0-9]") %>% as.integer())
df_totl <- df %>%
gather(group, totl, contains("Totl")) %>%
select(word, group, totl) %>%
mutate(group = str_extract(group, "[0-9]") %>% as.integer())
一旦我们有了这两个数据框,我们就会将它们重新合并在一起。我们从原始数据框中取出 word
和 Unique_words
列,然后按组添加 Occ 数据框,最后添加 Totl 数据框。终于,我们一行代码就可以完成你想要的计算了。
df_merge <- df %>%
select(word, Unique_words) %>%
left_join(df_occ, by = 'word') %>%
left_join(df_totl, by = c('word', 'group')) %>%
mutate(prob = (occ + 1) / (totl + Unique_words))
如果要将其转换回宽格式,可以使用 gather
函数的反函数,即 spread
.
df_wide <- df_merge %>%
select(word, group, prob) %>%
mutate(group = paste0("Prob_", group)) %>%
spread(group, prob)
这种方法的优点:
- 您的代码更易读,每个操作都在自己的行中,并且避免了方括号(这通常会产生难以阅读的代码)。
- 您的代码显示了中间步骤。
- 该方法更加灵活,希望也能简化其他处理步骤。