【发布时间】:2021-04-02 06:24:38
【问题描述】:
我想根据这些列中的所有值是否满足某个条件来重命名数据中的列。例如,在数值列中,如果所有值都大于 5,则将该列重命名为 large_values,否则保持列名不变。另一个例子,如果字符列中的所有值都没有& 字符,则将该列重命名为no_ampersand。
数据
library(tibble)
df <-
tribble(~age_1, ~age_2, ~string_1,
2, 7, "abc",
3, 8, "efg",
1, 11, "hi&",
10, 6, "klmn",
50, 100, "opq")
定义两个函数进行演示
- 向量元素是否大于某个值
is_larger_than_val <- function(x, y) {
all(x > y)
}
- 向量元素是否包含
&?
does_contain_ampersand <- function(x) {
all(grepl("&", x))
}
问题
那么使用这些函数,我怎样才能重命名df 的标题,这样当
is_larger_than_val(df$age_2, 5)
[1] TRUE
将age_2重命名为large_values,但以防万一
is_larger_than_val(df$age_1, 5)
[1] FALSE
将保持age_1 原样吗?
同样,因为
does_contain_ampersand(df$string_1)
[1] FALSE
将保持string_1 原样(但如果它是TRUE,那么string_1 将被重命名为no_ampersand)?
所需输出
给定当前数据,根据我在is_larger_than_val() 和does_contain_ampersand() 中指定的条件重命名应该返回:
# A tibble: 5 x 3
age_1 large_values string_1
<dbl> <dbl> <chr>
1 2 7 abc
2 3 8 efg
3 1 11 hi&
4 10 6 klmn
5 50 100 opq
我确信这可以通过嵌套一些 if else 语句来实现,但我想知道是否有更简单的方法(也许使用 tidyverse 技巧?)。
谢谢!
编辑
把问题放在上下文中
在下面@Ian 的评论之后,这是我的问题的上下文。- 我有一个源自
JSON文件的R数据对象。一旦我将JSON文件读入R,它就会以以下格式结束:
vec <- c(1, 2, 3)
names(vec) <- c("A", "B", "C")
my_data_object_as_list <- as.list(vec)
my_data_object_as_list
## $A
## [1] 1
## $B
## [1] 2
## $C
## [1] 3
- 我想构建一个函数,它接受
my_data_object_as_list并将其重新组织成一个表格。
require(tidyr)
require(dplyr)
require(tidyselect)
organize_in_table <- function(as_list_object) {
as_list_object %>%
bind_rows() %>%
pivot_longer(cols = tidyselect::everything())
}
organize_in_table(my_data_object_as_list)
## # A tibble: 3 x 2
## name value
## <chr> <dbl>
## 1 A 1
## 2 B 2
## 3 C 3
- 因为
organize_in_table()非常通用,所以它会返回一个表,其中的列名(name和value)并不表示每列的内容。为了解决这个问题,我想在organize_in_table()中添加一个purpose参数,下面是一个例子:
organize_in_table <-
function(as_list_object,
purpose = NULL) {
table <- as_list_object %>%
bind_rows() %>%
pivot_longer(cols = tidyselect::everything())
if (is.null(purpose)) {
return(table)
} else if (purpose == "match_letters_and_numbers") {
table <- rename(table, letters = name, numbers = value)
}
return(table)
}
现在,organize_in_table() 可以返回具有有意义名称的对象:
df_letters_and_numbers <-
organize_in_table(my_data_object_as_list, "match_letters_and_numbers")
> df_letters_and_numbers
## # A tibble: 3 x 2
## letters numbers
## <chr> <dbl>
## 1 A 1
## 2 B 2
## 3 C 3
-
这里我遇到了一个问题: 我怎么知道
df_letters_and_numbers[1]被正确命名为letters而df_letters_and_numbers[2]是numbers?我在什么基础上验证了——当我在organize_in_table()中重命名table时——第一列(name)全是字母,第二列(value)全是数字?我没有验证。
如果my_data_object_as_list 看起来像这样会怎样:
vec_2 <- c("A", "B", "C")
names(vec_2) <- c(1, 2, 3)
my_data_object_as_list_2 <- as.list(vec_2)
> my_data_object_as_list_2
## $`1`
## [1] "A"
## $`2`
## [1] "B"
## $`3`
## [1] "C"
如果我运行organize_in_table(my_data_object_as_list_2, "match_letters_and_numbers"),我会得到列名不匹配的数据框:
## # A tibble: 3 x 2
## letters numbers
## <chr> <chr>
## 1 1 A
## 2 2 B
## 3 3 C
底线
所以我的结论是,我必须根据要重命名的每一列的 content 在organize_in_table() 中调整重命名步骤。为此,我认为第一步应该是为我要执行的每个测试定义一个单独的函数(例如,列号中的所有值吗?所有值都是字母吗?)。而且因为我想让organize_in_table() 尽可能具有可扩展性,我希望它接受我可以为其构建测试功能的任何测试。
【问题讨论】:
-
您能解释一下您的实际最终目标是什么吗?如果我们无法理解最终目标是什么,就很难提供对您有用的答案。见The XY Problem。
-
谢谢。我已编辑问题以解决您的评论。
-
很确定你可以将这个问题简化为一个段落!
-
@geotheory,也许我可以,但我的原始版本很简洁,导致了 Ian 的评论。因此,为了完整性,我提供了更多信息。如果您愿意,请随时编辑帖子。我唯一的目标是明确并让人们帮助我解决问题。
-
@Emman 很公平,我接受大部分长度是加法
标签: r function dataframe dplyr