将逗号分隔的字符串转换为数字列

19
我有一个包含多个列的数据集,其中之一是反应时间列。这些反应时间用逗号分隔以表示同一参与者在不同试验中的反应时间。
例如:第1行(即参与者1的数据)在"反应时间"列下有以下内容。
reaction_times
2000,1450,1800,2200

因此,这些是参与者1在试次1,2,3,4的反应时间。

现在,我想创建一个新的数据集,其中这些试次的反应时间都形成单独的列。这样,我就可以计算每个试次的平均反应时间。

              trial 1  trial 2  trial 3  trial 4 
participant 1:   2000     1450     1800     2200

我尝试了reshape2包中的 colsplit 函数,但它似乎无法将我的数据拆分为新列(可能是因为我的数据都在一个单元格中)。

有什么建议吗?

4个回答

27

我认为您正在寻找strsplit()函数;

a = "2000,1450,1800,2200"
strsplit(a, ",")
[[1]]                                                                                                                                                       
[1] "2000" "1450" "1800" "2200"   

需要注意的是,strsplit返回一个列表,本例中只有一个元素。这是因为strsplit接受向量作为输入。因此,您也可以将单个单元字符的长向量放入函数中,并获得该向量的分割列表。在更相关的示例中,它看起来像:

# Create some example data
dat = data.frame(reaction_time = 
       apply(matrix(round(runif(100, 1, 2000)), 
                     25, 4), 1, paste, collapse = ","),
                     stringsAsFactors=FALSE)
splitdat = do.call("rbind", strsplit(dat$reaction_time, ","))
splitdat = data.frame(apply(splitdat, 2, as.numeric))
names(splitdat) = paste("trial", 1:4, sep = "")
head(splitdat)
  trial1 trial2 trial3 trial4
1    597   1071   1430    997
2    614    322   1242   1140
3   1522   1679     51   1120
4    225   1988   1938   1068
5    621    623   1174     55
6   1918   1828    136   1816

最后,计算每个人的平均值:

apply(splitdat, 1, mean)
[1] 1187.50  361.25  963.75 1017.00  916.25 1409.50  730.00 1310.75 1133.75
[10]  851.25  914.75  881.25  889.00 1014.75  676.75  850.50  805.00 1460.00
[19]  901.00 1443.50  507.25  691.50 1090.00  833.25  669.25

哇,保罗,回复得真快,谢谢!非常有效!如果我没记错的话,你还可以使用“colMeans”和“rowMeans”而不是'apply(splitdat, 1, mean)'?PS. 很抱歉我不能为你投票,显然我需要先拥有15点声望? - rvrvrv
你当然是对的,关于colMeans的问题。不过我认为使用apply也很好,因为它更加灵活。顺便问一下,你也来自荷兰吗? - Paul Hiemstra
谢谢!是的,我也来自荷兰 :) - rvrvrv

14
一种巧妙但有些笨重的方法是使用read.csvtextConnection结合起来使用。假设您的数据在数据框中,名为df:
x <- read.csv(textConnection(df[["reaction times"]]))

3
我认为这并不显得过于强硬。看起来是在灵巧地运用R。 - IRTFM
优雅的解决方案!很有趣看看我们的解决方案在处理大型数据集时速度如何相比。 - Paul Hiemstra
也可以完美地工作(我能同时批准两个作为解决方案吗?) - rvrvrv

11

这个问题很久以前就有了,但我从另一个最近的问题中发现它(似乎不相关)。

两个现有答案都很合适,但我想分享一个与我创建的名为“splitstackshape”的包相关的答案,它快速且语法简单。

下面是一些示例数据:

set.seed(1)
dat = data.frame(
  reaction_time = apply(matrix(round(
    runif(24, 1, 2000)), 6, 4), 1, paste, collapse = ","))

这是分割线:

library(splitstackshape)
cSplit(dat, "reaction_time", ",")
#    reaction_time_1 reaction_time_2 reaction_time_3 reaction_time_4
# 1:             532            1889            1374             761
# 2:             745            1322             769            1555
# 3:            1146            1259            1540            1869
# 4:            1817             125             996             425
# 5:             404             413            1436            1304
# 6:            1797             354            1984             252

而且,如果需要使用rowMeans

rowMeans(cSplit(dat, "reaction_time", ","))
# [1] 1139.00 1097.75 1453.50  840.75  889.25 1096.75

非常棒的软件包 - 感谢分享,使得事情变得更加简单明了! - rvrvrv

7

使用dplyr和tidyr的另一个选项,结合Paul Hiemstra的示例数据:

# create example data
data = data.frame(reaction_time = 
                     apply(matrix(round(runif(100, 1, 2000)), 
                                  25, 4), 1, paste, collapse = ","),
             stringsAsFactors=FALSE)
head(data)

# clean data
data2 <- data %>% mutate(split_reaction_time = str_split(as.character(reaction_time), ",")) %>% unnest(split_reaction_time) 
data2$col_names <- c("trial1", "trial2", "trial3", "trial4")
data2 <- data2 %>% spread(key = col_names, value = split_reaction_time) %>% select(-reaction_time)
head(data2)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接