整理 R 数据框中的数字数组
Tidying arrays of numbers in R data frame
如何整理下面的数据框
data.frame(a = c(1,2), values = c("[1.1, 1.2, 1.3]", "[2.1, 2.2]"))
a values
1 [1.1, 1.2, 1.3]
2 [2.1, 2.2]
结果应该是
data.frame(a = c(1,1,1,2,2), values = c(1.1, 1.2, 1.3, 2.1, 2.2))
a values
1 1.1
1 1.2
1 1.3
2 2.1
2 2.2
我们可以在list
和unnest
中提取str_extract_all
的数字
library(dplyr)
library(stringr)
library(tidyr)
df1 %>%
mutate(values = str_extract_all(values, "[0-9.]+")) %>%
unnest(values) %>%
type.convert(as.is = TRUE)
-输出
# A tibble: 5 × 2
a values
<int> <dbl>
1 1 1.1
2 1 1.2
3 1 1.3
4 2 2.1
5 2 2.2
或者另一种选择是使用 reticulate:py_eval
评估 python
对象,然后 unnest
list
列
library(reticulate)
df1 %>%
rowwise %>%
mutate(values = list(py_eval(values))) %>%
unnest(values)
-输出
# A tibble: 5 × 2
a values
<dbl> <dbl>
1 1 1.1
2 1 1.2
3 1 1.3
4 2 2.1
5 2 2.2
数据
df1 <- data.frame(a = c(1,2), values = c("[1.1, 1.2, 1.3]", "[2.1, 2.2]"))
另一个可能的解决方案:
library(tidyverse)
df <- data.frame(a = c(1,2), values = c("[1.1, 1.2, 1.3]", "[2.1, 2.2]"))
df %>%
separate(values, into=LETTERS[1:5], sep="\[|,|\]", fill="right",convert=T) %>%
pivot_longer(-a, values_drop_na = T) %>%
select(-name)
#> # A tibble: 5 × 2
#> a value
#> <dbl> <dbl>
#> 1 1 1.1
#> 2 1 1.2
#> 3 1 1.3
#> 4 2 2.1
#> 5 2 2.2
另一个基本 R 选项使用 eval
+ expression
+ gsub
with(
df,
type.convert(
setNames(
rev(
stack(
sapply(
setNames(values, a),
function(x) eval(str2expression(gsub("\[(.*)\]", "c(\1)", x)))
)
)
), names(df)
),
as.is = TRUE
)
)
给予
a values
1 1 1.1
2 1 1.2
3 1 1.3
4 2 2.1
5 2 2.2
刚刚意识到与@akrun 的回答类似,可以使用 jsonlite::fromJSON
将字符串转换为向量。这不会对数字格式做出任何特定假设,也不需要使用 Python.
df <- data.frame(a = c(1,2), values = c("[1.1, 1.2, 1.3]", "[2.1, 2.2]"))
df %>%
mutate(values = map(values, jsonlite::fromJSON)) %>%
unnest(values)
如何整理下面的数据框
data.frame(a = c(1,2), values = c("[1.1, 1.2, 1.3]", "[2.1, 2.2]"))
a values
1 [1.1, 1.2, 1.3]
2 [2.1, 2.2]
结果应该是
data.frame(a = c(1,1,1,2,2), values = c(1.1, 1.2, 1.3, 2.1, 2.2))
a values
1 1.1
1 1.2
1 1.3
2 2.1
2 2.2
我们可以在list
和unnest
str_extract_all
的数字
library(dplyr)
library(stringr)
library(tidyr)
df1 %>%
mutate(values = str_extract_all(values, "[0-9.]+")) %>%
unnest(values) %>%
type.convert(as.is = TRUE)
-输出
# A tibble: 5 × 2
a values
<int> <dbl>
1 1 1.1
2 1 1.2
3 1 1.3
4 2 2.1
5 2 2.2
或者另一种选择是使用 reticulate:py_eval
评估 python
对象,然后 unnest
list
列
library(reticulate)
df1 %>%
rowwise %>%
mutate(values = list(py_eval(values))) %>%
unnest(values)
-输出
# A tibble: 5 × 2
a values
<dbl> <dbl>
1 1 1.1
2 1 1.2
3 1 1.3
4 2 2.1
5 2 2.2
数据
df1 <- data.frame(a = c(1,2), values = c("[1.1, 1.2, 1.3]", "[2.1, 2.2]"))
另一个可能的解决方案:
library(tidyverse)
df <- data.frame(a = c(1,2), values = c("[1.1, 1.2, 1.3]", "[2.1, 2.2]"))
df %>%
separate(values, into=LETTERS[1:5], sep="\[|,|\]", fill="right",convert=T) %>%
pivot_longer(-a, values_drop_na = T) %>%
select(-name)
#> # A tibble: 5 × 2
#> a value
#> <dbl> <dbl>
#> 1 1 1.1
#> 2 1 1.2
#> 3 1 1.3
#> 4 2 2.1
#> 5 2 2.2
另一个基本 R 选项使用 eval
+ expression
+ gsub
with(
df,
type.convert(
setNames(
rev(
stack(
sapply(
setNames(values, a),
function(x) eval(str2expression(gsub("\[(.*)\]", "c(\1)", x)))
)
)
), names(df)
),
as.is = TRUE
)
)
给予
a values
1 1 1.1
2 1 1.2
3 1 1.3
4 2 2.1
5 2 2.2
刚刚意识到与@akrun 的回答类似,可以使用 jsonlite::fromJSON
将字符串转换为向量。这不会对数字格式做出任何特定假设,也不需要使用 Python.
df <- data.frame(a = c(1,2), values = c("[1.1, 1.2, 1.3]", "[2.1, 2.2]"))
df %>%
mutate(values = map(values, jsonlite::fromJSON)) %>%
unnest(values)