在 R 中导入和分析非矩形 .csv 文件
Importing and analysing non-rectangular .csv files in R
我正在从 Mathematica 转向 R,在其中我不需要在导入期间预测数据结构,特别是我不需要在导入之前预测数据的矩形性。
我有很多文件.csv
个文件格式如下:
tasty,chicken,cinnamon
not_tasty,butter,pepper,onion,cardamom,cayenne
tasty,olive_oil,pepper
okay,olive_oil,onion,potato,black_pepper
not_tasty,tomato,fenugreek,pepper,onion,potato
tasty,butter,cheese,wheat,ham
行的长度不同,并且只包含字符串。
在 R 中,我应该如何解决这个问题?
你试过什么?
我试过 read.table
:
dataImport <- read.table("data.csv", header = FALSE)
class(dataImport)
##[1] "data.frame"
dim(dataImport)
##[1] 6 1
dataImport[1]
##[1] tasty,chicken,cinnamon
##6 Levels: ...
我从文档中将其解释为单列,每个成分列表作为不同的行。我可能会如下提取前三行,每行都是 class
factor
但似乎包含的数据比我预期的要多:
dataImport[c(1,2,3),1]
## my rows
rowOne <- dataImport[c(1),1];
class(rowOne)
## "factor"
rowOne
## [1] tasty,chicken,cinnamon
## 6 Levels: not_tasty,butter,cheese [...]
就目前我所解决的问题而言,我将不胜感激有关 read.table
适用于此数据结构的建议。
我的目标是根据每行的第一个元素对数据进行分组,并分析每种食谱之间的差异。如果它有助于影响数据结构建议,在 Mathematica 中我会执行以下操作:
dataImport=Import["data.csv"];
tasty = Cases[dataImport, {"tasty", ingr__} :> {ingr}]
回答讨论
@G.Grothendieck 提供了使用 read.table
和使用 reshape2
包进行后续处理的解决方案 - 这似乎非常有用,我稍后会进行调查。这里的一般建议解决了我的问题,因此接受。
@MrFlick 关于使用 tm
包的建议对以后使用 DataframeSource
进行分析很有用
read.table 尝试 read.table
和 fill=TRUE
:
d1 <- read.table("data.csv", sep = ",", as.is = TRUE, fill = TRUE)
给予:
> d1
V1 V2 V3 V4 V5 V6
1 tasty chicken cinnamon
2 not_tasty butter pepper onion cardamom cayenne
3 tasty olive_oil pepper
4 okay olive_oil onion potato black_pepper
5 not_tasty tomato fenugreek pepper onion potato
6 tasty butter cheese wheat ham
read.table 与 NA
或用 NA 值填充空单元格添加 na.strings = ""
:
d2 <- read.table("data.csv", sep = ",", as.is = TRUE, fill = TRUE, na.strings = "")
给予:
> d2
V1 V2 V3 V4 V5 V6
1 tasty chicken cinnamon <NA> <NA> <NA>
2 not_tasty butter pepper onion cardamom cayenne
3 tasty olive_oil pepper <NA> <NA> <NA>
4 okay olive_oil onion potato black_pepper <NA>
5 not_tasty tomato fenugreek pepper onion potato
6 tasty butter cheese wheat ham <NA>
长格式
如果你想要长格式的:
library(reshape2)
long <- na.omit(melt(d2, id.var = c("id", "V1"))[-3])
long <- long[order(long$id), ]
给予:
> long
id V1 value
1 1 tasty chicken
7 1 tasty cinnamon
2 2 not_tasty butter
8 2 not_tasty pepper
14 2 not_tasty onion
20 2 not_tasty cardamom
26 2 not_tasty cayenne
3 3 tasty olive_oil
9 3 tasty pepper
4 4 okay olive_oil
10 4 okay onion
16 4 okay potato
22 4 okay black_pepper
5 5 not_tasty tomato
11 5 not_tasty fenugreek
17 5 not_tasty pepper
23 5 not_tasty onion
29 5 not_tasty potato
6 6 tasty butter
12 6 tasty cheese
18 6 tasty wheat
24 6 tasty ham
宽形式 0/1 二进制变量
要将变量部分表示为 0/1 二进制变量,试试这个:
wide <- cast(id + V1 ~ value, data = long)
wide[-(1:2)] <- 0 + !is.na(wide[-(1:2)])
给这个:
数据框中的列表
另一种表示形式是数据框中的以下列表,因此 ag$value
是一个字符向量列表:
ag <- aggregate(value ~., transform(long, value = as.character(value)), c)
ag <- ag[order(ag$id), ]
giving:
> ag
id V1 value
4 1 tasty chicken, cinnamon
1 2 not_tasty butter, pepper, onion, cardamom, cayenne
5 3 tasty olive_oil, pepper
3 4 okay olive_oil, onion, potato, black_pepper
2 5 not_tasty tomato, fenugreek, pepper, onion, potato
6 6 tasty butter, cheese, wheat, ham
> str(ag)
'data.frame': 6 obs. of 3 variables:
$ id : int 1 2 3 4 5 6
$ V1 : chr "tasty" "not_tasty" "tasty" "okay" ...
$ value:List of 6
..$ 15: chr "chicken" "cinnamon"
..$ 1 : chr "butter" "pepper" "onion" "cardamom" ...
..$ 17: chr "olive_oil" "pepper"
..$ 11: chr "olive_oil" "onion" "potato" "black_pepper"
..$ 6 : chr "tomato" "fenugreek" "pepper" "onion" ...
..$ 19: chr "butter" "cheese" "wheat" "ham"
我认为将您的数据放入 data.frame 或 data.table 中不会对您有多大帮助,因为这两种形式通常都采用矩形数据。如果你只想要一个字符向量列表,你可以读入它们。
strsplit(readLines("data.csv"), ",")
这完全取决于您读入数据后要对数据做什么。如果您打算使用现有功能,他们期望什么输入?
听起来您可能正在跟踪每个食谱中的术语。也许合适的数据结构是 tm
文本挖掘包中的 "corpus"。
我正在从 Mathematica 转向 R,在其中我不需要在导入期间预测数据结构,特别是我不需要在导入之前预测数据的矩形性。
我有很多文件.csv
个文件格式如下:
tasty,chicken,cinnamon
not_tasty,butter,pepper,onion,cardamom,cayenne
tasty,olive_oil,pepper
okay,olive_oil,onion,potato,black_pepper
not_tasty,tomato,fenugreek,pepper,onion,potato
tasty,butter,cheese,wheat,ham
行的长度不同,并且只包含字符串。
在 R 中,我应该如何解决这个问题?
你试过什么?
我试过 read.table
:
dataImport <- read.table("data.csv", header = FALSE)
class(dataImport)
##[1] "data.frame"
dim(dataImport)
##[1] 6 1
dataImport[1]
##[1] tasty,chicken,cinnamon
##6 Levels: ...
我从文档中将其解释为单列,每个成分列表作为不同的行。我可能会如下提取前三行,每行都是 class
factor
但似乎包含的数据比我预期的要多:
dataImport[c(1,2,3),1]
## my rows
rowOne <- dataImport[c(1),1];
class(rowOne)
## "factor"
rowOne
## [1] tasty,chicken,cinnamon
## 6 Levels: not_tasty,butter,cheese [...]
就目前我所解决的问题而言,我将不胜感激有关 read.table
适用于此数据结构的建议。
我的目标是根据每行的第一个元素对数据进行分组,并分析每种食谱之间的差异。如果它有助于影响数据结构建议,在 Mathematica 中我会执行以下操作:
dataImport=Import["data.csv"];
tasty = Cases[dataImport, {"tasty", ingr__} :> {ingr}]
回答讨论
@G.Grothendieck 提供了使用 read.table
和使用 reshape2
包进行后续处理的解决方案 - 这似乎非常有用,我稍后会进行调查。这里的一般建议解决了我的问题,因此接受。
@MrFlick 关于使用 tm
包的建议对以后使用 DataframeSource
read.table 尝试 read.table
和 fill=TRUE
:
d1 <- read.table("data.csv", sep = ",", as.is = TRUE, fill = TRUE)
给予:
> d1
V1 V2 V3 V4 V5 V6
1 tasty chicken cinnamon
2 not_tasty butter pepper onion cardamom cayenne
3 tasty olive_oil pepper
4 okay olive_oil onion potato black_pepper
5 not_tasty tomato fenugreek pepper onion potato
6 tasty butter cheese wheat ham
read.table 与 NA
或用 NA 值填充空单元格添加 na.strings = ""
:
d2 <- read.table("data.csv", sep = ",", as.is = TRUE, fill = TRUE, na.strings = "")
给予:
> d2
V1 V2 V3 V4 V5 V6
1 tasty chicken cinnamon <NA> <NA> <NA>
2 not_tasty butter pepper onion cardamom cayenne
3 tasty olive_oil pepper <NA> <NA> <NA>
4 okay olive_oil onion potato black_pepper <NA>
5 not_tasty tomato fenugreek pepper onion potato
6 tasty butter cheese wheat ham <NA>
长格式
如果你想要长格式的:
library(reshape2)
long <- na.omit(melt(d2, id.var = c("id", "V1"))[-3])
long <- long[order(long$id), ]
给予:
> long
id V1 value
1 1 tasty chicken
7 1 tasty cinnamon
2 2 not_tasty butter
8 2 not_tasty pepper
14 2 not_tasty onion
20 2 not_tasty cardamom
26 2 not_tasty cayenne
3 3 tasty olive_oil
9 3 tasty pepper
4 4 okay olive_oil
10 4 okay onion
16 4 okay potato
22 4 okay black_pepper
5 5 not_tasty tomato
11 5 not_tasty fenugreek
17 5 not_tasty pepper
23 5 not_tasty onion
29 5 not_tasty potato
6 6 tasty butter
12 6 tasty cheese
18 6 tasty wheat
24 6 tasty ham
宽形式 0/1 二进制变量
要将变量部分表示为 0/1 二进制变量,试试这个:
wide <- cast(id + V1 ~ value, data = long)
wide[-(1:2)] <- 0 + !is.na(wide[-(1:2)])
给这个:
数据框中的列表
另一种表示形式是数据框中的以下列表,因此 ag$value
是一个字符向量列表:
ag <- aggregate(value ~., transform(long, value = as.character(value)), c)
ag <- ag[order(ag$id), ]
giving:
> ag
id V1 value
4 1 tasty chicken, cinnamon
1 2 not_tasty butter, pepper, onion, cardamom, cayenne
5 3 tasty olive_oil, pepper
3 4 okay olive_oil, onion, potato, black_pepper
2 5 not_tasty tomato, fenugreek, pepper, onion, potato
6 6 tasty butter, cheese, wheat, ham
> str(ag)
'data.frame': 6 obs. of 3 variables:
$ id : int 1 2 3 4 5 6
$ V1 : chr "tasty" "not_tasty" "tasty" "okay" ...
$ value:List of 6
..$ 15: chr "chicken" "cinnamon"
..$ 1 : chr "butter" "pepper" "onion" "cardamom" ...
..$ 17: chr "olive_oil" "pepper"
..$ 11: chr "olive_oil" "onion" "potato" "black_pepper"
..$ 6 : chr "tomato" "fenugreek" "pepper" "onion" ...
..$ 19: chr "butter" "cheese" "wheat" "ham"
我认为将您的数据放入 data.frame 或 data.table 中不会对您有多大帮助,因为这两种形式通常都采用矩形数据。如果你只想要一个字符向量列表,你可以读入它们。
strsplit(readLines("data.csv"), ",")
这完全取决于您读入数据后要对数据做什么。如果您打算使用现有功能,他们期望什么输入?
听起来您可能正在跟踪每个食谱中的术语。也许合适的数据结构是 tm
文本挖掘包中的 "corpus"。