如何将集合变成集合成员的指标?
How do I turn sets into indicators of set membership?
我拥有的数据是每次观察一组"flavors"。我想将这些集合(在 PostgreSQL 中以 text[]
数组的形式存在)转换为指示各种口味是否存在的指标,因为我想检查口味是如何组合在一起或不组合在一起的。
我现在的工作正常,但我实际上想要 运行 更复杂的变体,我有一种预感,我将数据汇总在一起的方式远没有它可能的那么优雅。我尝试使用 tidyr
和 dplyr
包,但看不到如何应用这些包。
有没有更好的方法(使用R)?
下面是一些示例代码:
library("PostgreSQL")
pg <- dbConnect(PostgreSQL())
# Make the data set in the form I have it.
rs <- dbGetQuery(pg, "
DROP TABLE IF EXISTS icecream ;
CREATE TABLE icecream (id text, date date, flavours text[]);
INSERT INTO icecream (id, date, flavours) VALUES
('a', '2013-01-01', ARRAY['Chocolate', 'Vanilla']),
('b', '2013-01-01', ARRAY['Strawberry', 'Vanilla']),
('b', '2013-02-01', ARRAY['Raspberry', 'Lemon']),
('c', '2013-01-01', ARRAY['Raspberry', 'Blueberry']);")
# Get data in an R-friendly format
df <- dbGetQuery(pg, "
SELECT id, date, UNNEST(flavours) AS flavour
FROM icecream;")
rs <- dbDisconnect(pg)
# Rearrange data and look at correlations
library(reshape2)
temp <- dcast(df, id + date ~ flavour, value.var="flavour")
temp[, -c(1,2)] <- !is.na(temp[, -c(1,2)])
cor(temp[, -c(1,2)])
数据最终如下所示:
id date Blueberry Chocolate Lemon Raspberry Strawberry Vanilla
1 a 2013-01-01 FALSE TRUE FALSE FALSE FALSE TRUE
2 b 2013-01-01 FALSE FALSE FALSE FALSE TRUE TRUE
3 b 2013-02-01 FALSE FALSE TRUE TRUE FALSE FALSE
4 c 2013-01-01 TRUE FALSE FALSE TRUE FALSE FALSE
下面是我想要进行的分析类型的示例:
> cor(temp[, -c(1,2)])
Blueberry Chocolate Lemon Raspberry Strawberry Vanilla
Blueberry 1.0000000 -0.3333333 -0.3333333 0.5773503 -0.3333333 -0.5773503
Chocolate -0.3333333 1.0000000 -0.3333333 -0.5773503 -0.3333333 0.5773503
Lemon -0.3333333 -0.3333333 1.0000000 0.5773503 -0.3333333 -0.5773503
Raspberry 0.5773503 -0.5773503 0.5773503 1.0000000 -0.5773503 -1.0000000
Strawberry -0.3333333 -0.3333333 -0.3333333 -0.5773503 1.0000000 0.5773503
Vanilla -0.5773503 0.5773503 -0.5773503 -1.0000000 0.5773503 1.0000000
要跳过 PostgreSQL,我想可以使用此信息将 df
放在一起。我包括 PostgreSQL 以防万一更优雅的解决方案更有效地使用 PostgreSQL。
dput(df)
structure(list(id = c("a", "a", "b", "b", "b", "b", "c", "c"),
date = structure(c(15706, 15706, 15706, 15706, 15737, 15737,
15706, 15706), class = "Date"), flavour = c("Chocolate",
"Vanilla", "Strawberry", "Vanilla", "Raspberry", "Lemon",
"Raspberry", "Blueberry")), .Names = c("id", "date", "flavour"
), row.names = c(NA, 8L), class = "data.frame")
任何 postgres 解决方案都会变得不那么优雅。您必须使用 crosstab
,这将需要为您的每种口味定义列。
这是 dplyr 和 tidyr 的方法:
library(dplyr)
library(tidyr)
df %>%
mutate_(indicator=~TRUE) %>%
spread('flavour', 'indicator', fill=FALSE)
基于 @Matthew Plourde 的回答,这里是函数内置的版本:
set_to_indicator <- function(df, var) {
library(dplyr)
library(tidyr)
df %>%
mutate_(indicator=~TRUE) %>%
spread_(var, "indicator", fill=FALSE)
}
set_to_indicator(df, "flavour")
请注意,我在这里使用的是 spread
的 "standard evaluation" 版本(即 spread_
)。 (添加这么多代码作为注释似乎很困难,所以我把它作为一个单独的答案。)
我拥有的数据是每次观察一组"flavors"。我想将这些集合(在 PostgreSQL 中以 text[]
数组的形式存在)转换为指示各种口味是否存在的指标,因为我想检查口味是如何组合在一起或不组合在一起的。
我现在的工作正常,但我实际上想要 运行 更复杂的变体,我有一种预感,我将数据汇总在一起的方式远没有它可能的那么优雅。我尝试使用 tidyr
和 dplyr
包,但看不到如何应用这些包。
有没有更好的方法(使用R)?
下面是一些示例代码:
library("PostgreSQL")
pg <- dbConnect(PostgreSQL())
# Make the data set in the form I have it.
rs <- dbGetQuery(pg, "
DROP TABLE IF EXISTS icecream ;
CREATE TABLE icecream (id text, date date, flavours text[]);
INSERT INTO icecream (id, date, flavours) VALUES
('a', '2013-01-01', ARRAY['Chocolate', 'Vanilla']),
('b', '2013-01-01', ARRAY['Strawberry', 'Vanilla']),
('b', '2013-02-01', ARRAY['Raspberry', 'Lemon']),
('c', '2013-01-01', ARRAY['Raspberry', 'Blueberry']);")
# Get data in an R-friendly format
df <- dbGetQuery(pg, "
SELECT id, date, UNNEST(flavours) AS flavour
FROM icecream;")
rs <- dbDisconnect(pg)
# Rearrange data and look at correlations
library(reshape2)
temp <- dcast(df, id + date ~ flavour, value.var="flavour")
temp[, -c(1,2)] <- !is.na(temp[, -c(1,2)])
cor(temp[, -c(1,2)])
数据最终如下所示:
id date Blueberry Chocolate Lemon Raspberry Strawberry Vanilla
1 a 2013-01-01 FALSE TRUE FALSE FALSE FALSE TRUE
2 b 2013-01-01 FALSE FALSE FALSE FALSE TRUE TRUE
3 b 2013-02-01 FALSE FALSE TRUE TRUE FALSE FALSE
4 c 2013-01-01 TRUE FALSE FALSE TRUE FALSE FALSE
下面是我想要进行的分析类型的示例:
> cor(temp[, -c(1,2)])
Blueberry Chocolate Lemon Raspberry Strawberry Vanilla
Blueberry 1.0000000 -0.3333333 -0.3333333 0.5773503 -0.3333333 -0.5773503
Chocolate -0.3333333 1.0000000 -0.3333333 -0.5773503 -0.3333333 0.5773503
Lemon -0.3333333 -0.3333333 1.0000000 0.5773503 -0.3333333 -0.5773503
Raspberry 0.5773503 -0.5773503 0.5773503 1.0000000 -0.5773503 -1.0000000
Strawberry -0.3333333 -0.3333333 -0.3333333 -0.5773503 1.0000000 0.5773503
Vanilla -0.5773503 0.5773503 -0.5773503 -1.0000000 0.5773503 1.0000000
要跳过 PostgreSQL,我想可以使用此信息将 df
放在一起。我包括 PostgreSQL 以防万一更优雅的解决方案更有效地使用 PostgreSQL。
dput(df)
structure(list(id = c("a", "a", "b", "b", "b", "b", "c", "c"),
date = structure(c(15706, 15706, 15706, 15706, 15737, 15737,
15706, 15706), class = "Date"), flavour = c("Chocolate",
"Vanilla", "Strawberry", "Vanilla", "Raspberry", "Lemon",
"Raspberry", "Blueberry")), .Names = c("id", "date", "flavour"
), row.names = c(NA, 8L), class = "data.frame")
任何 postgres 解决方案都会变得不那么优雅。您必须使用 crosstab
,这将需要为您的每种口味定义列。
这是 dplyr 和 tidyr 的方法:
library(dplyr)
library(tidyr)
df %>%
mutate_(indicator=~TRUE) %>%
spread('flavour', 'indicator', fill=FALSE)
基于 @Matthew Plourde 的回答,这里是函数内置的版本:
set_to_indicator <- function(df, var) {
library(dplyr)
library(tidyr)
df %>%
mutate_(indicator=~TRUE) %>%
spread_(var, "indicator", fill=FALSE)
}
set_to_indicator(df, "flavour")
请注意,我在这里使用的是 spread
的 "standard evaluation" 版本(即 spread_
)。 (添加这么多代码作为注释似乎很困难,所以我把它作为一个单独的答案。)