将用 SPSS 编写的小型数据集转换为 CSV
Convert a small dataset written in SPSS to CSV
我有一个用 SPSS 语法编写的小数据集,它来自 Table 5.3 p. 189 of this book(在页槽中键入 210
以查看 table).
我想知道是否有办法将此数据转换为 .csv
文件? (后面我想用R
里面的数据)
# SPSS Code:
DATA LIST FREE/gpid anx socskls assert.
BEGIN DATA.
1 5 3 3 1 5 4 3 1 4 5 4 1 4 5 4
1 3 5 5 1 4 5 4 1 4 5 5 1 4 4 4
1 5 4 3 1 5 4 3 1 4 4 4
2 6 2 1 2 6 2 2 2 5 2 3 2 6 2 2
2 4 4 4 2 7 1 1 2 5 4 3 2 5 2 3
2 5 3 3 2 5 4 3 2 6 2 3
3 4 4 4 3 4 3 3 3 4 4 4 3 4 5 5
3 4 5 5 3 4 4 4 3 4 5 4 3 4 6 5
3 4 4 4 3 5 3 3 3 4 4 4
END DATA.
编辑 - 为了检查答案,我在此处添加数据在 SPSS 中读取后的实际方式:
gpid anx socskls assert
1 5 3 3
1 5 4 3
1 4 5 4
1 4 5 4
1 3 5 5
1 4 5 4
1 4 5 5
1 4 4 4
1 5 4 3
1 5 4 3
1 4 4 4
2 6 2 1
2 6 2 2
2 5 2 3
2 6 2 2
2 4 4 4
2 7 1 1
2 5 4 3
2 5 2 3
2 5 3 3
2 5 4 3
2 6 2 3
3 4 4 4
3 4 3 3
3 4 4 4
3 4 5 5
3 4 5 5
3 4 4 4
3 4 5 4
3 4 6 5
3 4 4 4
3 5 3 3
3 4 4 4
这需要在记事本或类似工具中进行一些手动清理,以正确的格式放置数据。但本质上,这可以使用以下内容导入
df <- data.frame(
gpid = c(1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,
2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3),
anx = c(5,5,4,4,3,4,4,4,5,5,4,6,6,5,6,
4,7,5,5,5,5,6,4,4,4,4,4,4,4,4,4,5,4),
socskls = c(3,4,5,5,5,5,5,4,4,4,4,2,2,2,2,
4,1,4,2,3,4,2,4,3,4,5,5,4,5,6,4,3,4),
assert = c(3,3,4,4,5,4,5,4,3,3,4,1,2,3,2,
4,1,3,3,3,3,3,4,3,4,5,5,4,4,5,4,3,4)
)
write.csv(df, "df.csv", row.names = F)
请注意,前 4 个值(1、5、3、3)是第 1 行的 gpid、anx、socskls 和断言值。而值 1、5、4、3 似乎在SPSS 语法中粘贴数据的下一列(即从左到右阅读语法的下 4 个值)实际上是参与者 10 的值。
注意:我假设您没有安装 SPSS。如果你做了最简单的选择,那就是使用 SPSS 语法在 SPSS 中创建数据集,然后导出到 R。
使用readLines
和一些字符串处理工具。
tmp <- readLines("spss1.txt") ## read from .txt
tmp <- trimws(gsub("[A-Z/.]", "", tmp)) ## remove caps and specials
nm <- strsplit(tmp[[1]], " ")[[1]] ## split names
tmp <- unlist(strsplit(tmp[3:11], "\s{2,}") ) ## split data blocks
最后,在空格处拆分得到结果。
dat <- setNames(
type.convert(do.call(rbind.data.frame, strsplit(tmp, "\s"))),
nm)
结果
dat
# gpid anx socskls assert
# 1 1 5 3 3
# 2 1 5 4 3
# 3 1 4 5 4
# 4 1 4 5 4
# 5 1 3 5 5
# 6 1 4 5 4
# 7 1 4 5 5
# 8 1 4 4 4
# 9 1 5 4 3
# 10 1 5 4 3
# 11 1 4 4 4
# 12 2 6 2 1
# 13 2 6 2 2
# 14 2 5 2 3
# 15 2 6 2 2
# 16 2 4 4 4
# 17 2 7 1 1
# 18 2 5 4 3
# 19 2 5 2 3
# 20 2 5 3 3
# 21 2 5 4 3
# 22 2 6 2 3
# 23 3 4 4 4
# 24 3 4 3 3
# 25 3 4 4 4
# 26 3 4 5 5
# 27 3 4 5 5
# 28 3 4 4 4
# 29 3 4 5 4
# 30 3 4 6 5
# 31 3 4 4 4
# 32 3 5 3 3
# 33 3 4 4 4
注意: 结果与 @emily-kothe 的方法相同。也许作者使用了不同的数据或者您的 manova 方法有缺陷?
如果我没理解错,数据集的第1、5、9、13列属于变量gpid
,第2、6、10、14列属于变量anx
, 等等。所以,我们需要
- 从宽格式重塑为长格式
- 具有多个测量变量
- 其中每个度量变量跨越多个列
- 并且缺少某些值。
条条大路通罗马。
这就是我使用我最喜欢的工具会做的事情。特别是,此方法使用 data.table::melt()
的功能同时重塑多个度量列。不需要在文本编辑器中手动清理数据部分。
生成的数据集 result
可以在 OP 请求的任何后续 R
代码中直接使用。使用.csv
文件就不用绕路了(不过,可以随意将result
保存为.csv
文件)。
library(data.table)
library(magrittr)
cols <- c("gpid", "anx", "socskls", "assert")
raw <- fread(text = "
1 5 3 3 1 5 4 3 1 4 5 4 1 4 5 4
1 3 5 5 1 4 5 4 1 4 5 5 1 4 4 4
1 5 4 3 1 5 4 3 1 4 4 4
2 6 2 1 2 6 2 2 2 5 2 3 2 6 2 2
2 4 4 4 2 7 1 1 2 5 4 3 2 5 2 3
2 5 3 3 2 5 4 3 2 6 2 3
3 4 4 4 3 4 3 3 3 4 4 4 3 4 5 5
3 4 5 5 3 4 4 4 3 4 5 4 3 4 6 5
3 4 4 4 3 5 3 3 3 4 4 4",
fill = TRUE)
mv <- colnames(raw) %>%
matrix(ncol = 4L, byrow = TRUE) %>%
as.data.table() %>%
setnames(new = cols)
result <- melt(raw, measure.vars = mv, na.rm = TRUE)[
order(rowid(variable))][
, variable := NULL]
result
gpid anx socskls assert
1: 1 5 3 3
2: 1 5 4 3
3: 1 4 5 4
4: 1 4 5 4
5: 1 3 5 5
6: 1 4 5 4
7: 1 4 5 5
8: 1 4 4 4
9: 1 5 4 3
10: 1 5 4 3
11: 1 4 4 4
12: 2 6 2 1
13: 2 6 2 2
14: 2 5 2 3
15: 2 6 2 2
16: 2 4 4 4
17: 2 7 1 1
18: 2 5 4 3
19: 2 5 2 3
20: 2 5 3 3
21: 2 5 4 3
22: 2 6 2 3
23: 3 4 4 4
24: 3 4 3 3
25: 3 4 4 4
26: 3 4 5 5
27: 3 4 5 5
28: 3 4 4 4
29: 3 4 5 4
30: 3 4 6 5
31: 3 4 4 4
32: 3 5 3 3
33: 3 4 4 4
gpid anx socskls assert
一些解释
fread()
returns a data.table raw
默认列名 V1
, V2
, ... V16
并用 NA
填充缺失值
mv
是一个data.table,表示raw
的哪些列属于每个目标变量:
mv
gpid anx socskls assert
1: V1 V2 V3 V4
2: V5 V6 V7 V8
3: V9 V10 V11 V12
4: V13 V14 V15 V16
此信息由 melt()
使用。 melt()
还会从生成的长格式中删除具有缺失值的行。
整形后,行按可变编号排序,但需要使用 rowid(variable)
按原始行顺序重新排序。最后,删除 variable
列。
编辑:改进版本[=62=]
再想一想,这里是代码的简化版本,它跳过了 mv
的创建并使用了 data.table
chaining:
library(data.table)
cols <- c("gpid", "anx", "socskls", "assert")
result <- fread(
text = "
1 5 3 3 1 5 4 3 1 4 5 4 1 4 5 4
1 3 5 5 1 4 5 4 1 4 5 5 1 4 4 4
1 5 4 3 1 5 4 3 1 4 4 4
2 6 2 1 2 6 2 2 2 5 2 3 2 6 2 2
2 4 4 4 2 7 1 1 2 5 4 3 2 5 2 3
2 5 3 3 2 5 4 3 2 6 2 3
3 4 4 4 3 4 3 3 3 4 4 4 3 4 5 5
3 4 5 5 3 4 4 4 3 4 5 4 3 4 6 5
3 4 4 4 3 5 3 3 3 4 4 4",
fill = TRUE, col.names = rep(cols, 4L))[
, melt(.SD, measure.vars = patterns(cols), value.name = cols, na.rm = TRUE)][
order(rowid(variable))][
, variable := NULL][]
result
此处,在对 fread()
的调用中对列进行了重命名。在这种情况下,重复的列名是可取的(与通常的用例相反),因为 patterns()
函数在随后调用 melt()
时使用重复的列名来组合属于一个度量的列变量。
我有一个用 SPSS 语法编写的小数据集,它来自 Table 5.3 p. 189 of this book(在页槽中键入 210
以查看 table).
我想知道是否有办法将此数据转换为 .csv
文件? (后面我想用R
里面的数据)
# SPSS Code:
DATA LIST FREE/gpid anx socskls assert.
BEGIN DATA.
1 5 3 3 1 5 4 3 1 4 5 4 1 4 5 4
1 3 5 5 1 4 5 4 1 4 5 5 1 4 4 4
1 5 4 3 1 5 4 3 1 4 4 4
2 6 2 1 2 6 2 2 2 5 2 3 2 6 2 2
2 4 4 4 2 7 1 1 2 5 4 3 2 5 2 3
2 5 3 3 2 5 4 3 2 6 2 3
3 4 4 4 3 4 3 3 3 4 4 4 3 4 5 5
3 4 5 5 3 4 4 4 3 4 5 4 3 4 6 5
3 4 4 4 3 5 3 3 3 4 4 4
END DATA.
编辑 - 为了检查答案,我在此处添加数据在 SPSS 中读取后的实际方式:
gpid anx socskls assert
1 5 3 3
1 5 4 3
1 4 5 4
1 4 5 4
1 3 5 5
1 4 5 4
1 4 5 5
1 4 4 4
1 5 4 3
1 5 4 3
1 4 4 4
2 6 2 1
2 6 2 2
2 5 2 3
2 6 2 2
2 4 4 4
2 7 1 1
2 5 4 3
2 5 2 3
2 5 3 3
2 5 4 3
2 6 2 3
3 4 4 4
3 4 3 3
3 4 4 4
3 4 5 5
3 4 5 5
3 4 4 4
3 4 5 4
3 4 6 5
3 4 4 4
3 5 3 3
3 4 4 4
这需要在记事本或类似工具中进行一些手动清理,以正确的格式放置数据。但本质上,这可以使用以下内容导入
df <- data.frame(
gpid = c(1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,
2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3),
anx = c(5,5,4,4,3,4,4,4,5,5,4,6,6,5,6,
4,7,5,5,5,5,6,4,4,4,4,4,4,4,4,4,5,4),
socskls = c(3,4,5,5,5,5,5,4,4,4,4,2,2,2,2,
4,1,4,2,3,4,2,4,3,4,5,5,4,5,6,4,3,4),
assert = c(3,3,4,4,5,4,5,4,3,3,4,1,2,3,2,
4,1,3,3,3,3,3,4,3,4,5,5,4,4,5,4,3,4)
)
write.csv(df, "df.csv", row.names = F)
请注意,前 4 个值(1、5、3、3)是第 1 行的 gpid、anx、socskls 和断言值。而值 1、5、4、3 似乎在SPSS 语法中粘贴数据的下一列(即从左到右阅读语法的下 4 个值)实际上是参与者 10 的值。
注意:我假设您没有安装 SPSS。如果你做了最简单的选择,那就是使用 SPSS 语法在 SPSS 中创建数据集,然后导出到 R。
使用readLines
和一些字符串处理工具。
tmp <- readLines("spss1.txt") ## read from .txt
tmp <- trimws(gsub("[A-Z/.]", "", tmp)) ## remove caps and specials
nm <- strsplit(tmp[[1]], " ")[[1]] ## split names
tmp <- unlist(strsplit(tmp[3:11], "\s{2,}") ) ## split data blocks
最后,在空格处拆分得到结果。
dat <- setNames(
type.convert(do.call(rbind.data.frame, strsplit(tmp, "\s"))),
nm)
结果
dat
# gpid anx socskls assert
# 1 1 5 3 3
# 2 1 5 4 3
# 3 1 4 5 4
# 4 1 4 5 4
# 5 1 3 5 5
# 6 1 4 5 4
# 7 1 4 5 5
# 8 1 4 4 4
# 9 1 5 4 3
# 10 1 5 4 3
# 11 1 4 4 4
# 12 2 6 2 1
# 13 2 6 2 2
# 14 2 5 2 3
# 15 2 6 2 2
# 16 2 4 4 4
# 17 2 7 1 1
# 18 2 5 4 3
# 19 2 5 2 3
# 20 2 5 3 3
# 21 2 5 4 3
# 22 2 6 2 3
# 23 3 4 4 4
# 24 3 4 3 3
# 25 3 4 4 4
# 26 3 4 5 5
# 27 3 4 5 5
# 28 3 4 4 4
# 29 3 4 5 4
# 30 3 4 6 5
# 31 3 4 4 4
# 32 3 5 3 3
# 33 3 4 4 4
注意: 结果与 @emily-kothe 的方法相同。也许作者使用了不同的数据或者您的 manova 方法有缺陷?
如果我没理解错,数据集的第1、5、9、13列属于变量gpid
,第2、6、10、14列属于变量anx
, 等等。所以,我们需要
- 从宽格式重塑为长格式
- 具有多个测量变量
- 其中每个度量变量跨越多个列
- 并且缺少某些值。
条条大路通罗马。
这就是我使用我最喜欢的工具会做的事情。特别是,此方法使用 data.table::melt()
的功能同时重塑多个度量列。不需要在文本编辑器中手动清理数据部分。
生成的数据集 result
可以在 OP 请求的任何后续 R
代码中直接使用。使用.csv
文件就不用绕路了(不过,可以随意将result
保存为.csv
文件)。
library(data.table)
library(magrittr)
cols <- c("gpid", "anx", "socskls", "assert")
raw <- fread(text = "
1 5 3 3 1 5 4 3 1 4 5 4 1 4 5 4
1 3 5 5 1 4 5 4 1 4 5 5 1 4 4 4
1 5 4 3 1 5 4 3 1 4 4 4
2 6 2 1 2 6 2 2 2 5 2 3 2 6 2 2
2 4 4 4 2 7 1 1 2 5 4 3 2 5 2 3
2 5 3 3 2 5 4 3 2 6 2 3
3 4 4 4 3 4 3 3 3 4 4 4 3 4 5 5
3 4 5 5 3 4 4 4 3 4 5 4 3 4 6 5
3 4 4 4 3 5 3 3 3 4 4 4",
fill = TRUE)
mv <- colnames(raw) %>%
matrix(ncol = 4L, byrow = TRUE) %>%
as.data.table() %>%
setnames(new = cols)
result <- melt(raw, measure.vars = mv, na.rm = TRUE)[
order(rowid(variable))][
, variable := NULL]
result
gpid anx socskls assert 1: 1 5 3 3 2: 1 5 4 3 3: 1 4 5 4 4: 1 4 5 4 5: 1 3 5 5 6: 1 4 5 4 7: 1 4 5 5 8: 1 4 4 4 9: 1 5 4 3 10: 1 5 4 3 11: 1 4 4 4 12: 2 6 2 1 13: 2 6 2 2 14: 2 5 2 3 15: 2 6 2 2 16: 2 4 4 4 17: 2 7 1 1 18: 2 5 4 3 19: 2 5 2 3 20: 2 5 3 3 21: 2 5 4 3 22: 2 6 2 3 23: 3 4 4 4 24: 3 4 3 3 25: 3 4 4 4 26: 3 4 5 5 27: 3 4 5 5 28: 3 4 4 4 29: 3 4 5 4 30: 3 4 6 5 31: 3 4 4 4 32: 3 5 3 3 33: 3 4 4 4 gpid anx socskls assert
一些解释
fread()
returns a data.table raw
默认列名 V1
, V2
, ... V16
并用 NA
mv
是一个data.table,表示raw
的哪些列属于每个目标变量:
mv
gpid anx socskls assert 1: V1 V2 V3 V4 2: V5 V6 V7 V8 3: V9 V10 V11 V12 4: V13 V14 V15 V16
此信息由 melt()
使用。 melt()
还会从生成的长格式中删除具有缺失值的行。
整形后,行按可变编号排序,但需要使用 rowid(variable)
按原始行顺序重新排序。最后,删除 variable
列。
编辑:改进版本[=62=]
再想一想,这里是代码的简化版本,它跳过了 mv
的创建并使用了 data.table
chaining:
library(data.table)
cols <- c("gpid", "anx", "socskls", "assert")
result <- fread(
text = "
1 5 3 3 1 5 4 3 1 4 5 4 1 4 5 4
1 3 5 5 1 4 5 4 1 4 5 5 1 4 4 4
1 5 4 3 1 5 4 3 1 4 4 4
2 6 2 1 2 6 2 2 2 5 2 3 2 6 2 2
2 4 4 4 2 7 1 1 2 5 4 3 2 5 2 3
2 5 3 3 2 5 4 3 2 6 2 3
3 4 4 4 3 4 3 3 3 4 4 4 3 4 5 5
3 4 5 5 3 4 4 4 3 4 5 4 3 4 6 5
3 4 4 4 3 5 3 3 3 4 4 4",
fill = TRUE, col.names = rep(cols, 4L))[
, melt(.SD, measure.vars = patterns(cols), value.name = cols, na.rm = TRUE)][
order(rowid(variable))][
, variable := NULL][]
result
此处,在对 fread()
的调用中对列进行了重命名。在这种情况下,重复的列名是可取的(与通常的用例相反),因为 patterns()
函数在随后调用 melt()
时使用重复的列名来组合属于一个度量的列变量。