43

我想获取一个带有字符和数字的数据框,并将每一行的所有元素连接成一个字符串,该字符串将作为单个元素存储在向量中。例如,我制作了一个字母和数字的数据框,然后我想通过粘贴函数连接第一行,并希望返回值“A1”

df <- data.frame(letters = LETTERS[1:5], numbers = 1:5)
df

##   letters numbers
## 1       A       1
## 2       B       2
## 3       C       3
## 4       D       4
## 5       E       5

paste(df[1,], sep =".")
## [1] "1" "1"

因此 paste 将行中的每个元素转换为与“相应级别的索引”相对应的整数,就好像它是一个因子一样,并将其保持为长度为 2 的向量。(我知道/相信被强制为字符的因素以这种方式表现,但由于 R 根本没有将 df[1,] 存储为一个因素(由 is.factor() 测试,我无法验证它实际上是一个级别的索引)

is.factor(df[1,])
## [1] FALSE
is.vector(df[1,])
## [1] FALSE

因此,如果它不是向量,那么它的行为很奇怪是有道理的,但我不能将它强制转换为向量

> is.vector(as.vector(df[1,]))
[1] FALSE

使用as.character似乎对我的尝试没有帮助

谁能解释这种行为?

4

4 回答 4

67

当其他人专注于为什么您的代码不起作用以及如何改进它时,我将尝试更多地关注获得您想要的结果。根据您的描述,您似乎可以使用粘贴轻松实现您想要的效果:

df <- data.frame(letters = LETTERS[1:5], numbers = 1:5, stringsAsFactors=FALSE)
paste(df$letters, df$numbers, sep=""))

## [1] "A1" "B2" "C3" "D4" "E5"

如果您不想使用该参数,您可以更改df$letters为使用字符。df$letters <- as.character(df$letters)stringsAsFactors

但是让我们假设这不是你想要的。假设您有数百列,并且您想将它们全部粘贴在一起。我们也可以使用您的最小示例来做到这一点:

df_args <- c(df, sep="")
do.call(paste, df_args)

## [1] "A1" "B2" "C3" "D4" "E5"

编辑:替代方法和解释:

我意识到您遇到的问题是您正在使用一个因素和您正在使用sep参数而不是collapse(正如@adibender 拾取的那样)这一事实的组合。不同之处在于sep给出两个独立向量之间的分隔符并collapse给出向量内的分隔符。当你使用 时df[1,],你提供了一个向量paste,因此你必须使用collapse参数。使用您获取每一行并将它们连接起来的想法,以下代码行将完全符合您的要求:

apply(df, 1, paste, collapse="")

好的,现在进行解释:

为什么as.list行不通?

as.list将对象转换为列表。所以它确实有效。它会将您的数据框转换为列表,然后忽略该sep=""参数。c将对象组合在一起。从技术上讲,数据框只是一个列表,其中每一列都是一个元素,所有元素必须具有相同的长度。因此,当我将它与 结合使用时sep="",它就变成了一个常规列表,其中数据框的列作为元素。

为什么使用do.call

do.call允许您使用命名列表作为其参数调用函数。您不能直接将列表放入paste,因为它不喜欢数据框。它是为连接向量而设计的。所以请记住,这dfargs是一个包含字母向量、数字向量和 sep 的列表,它是一个长度为 1 的向量,仅包含“”。当我使用do.call时,产生的粘贴功能本质上是paste(letters, numbers, sep).
但是,如果我的原始数据框有列"letters", "numbers", "squigs", "blargs",然后我像以前一样添加分隔符怎么办?然后粘贴功能do.call看起来像:

paste(letters, numbers, squigs, blargs, sep)

所以你看到它适用于任意数量的列。

于 2012-12-19T01:32:54.033 回答
5

对于那些使用library(tidyverse),您可以简单地使用该unite功能。

 new.df <- df%>%
 unite(together, letters, numbers, sep="")

这将为您提供一个名为togetherA1、B2 等的新列。

于 2017-05-11T19:04:28.873 回答
4

这确实有点奇怪,但这也是应该发生的事情。当您像以前一样创建data.frame时,列letters存储为factor. 自然因素没有排序,因此当as.numeric()应用于一个因素时,它返回因素的排序。例如:

> df[, 1]
[1] A B C D E
Levels: A B C D E
> as.numeric(df[, 1])
[1] 1 2 3 4 5

A是因子的第一级,df[, 1]因此在应用时A转换为值。这就是你打电话时发生的事情。由于第 1 列和第 2 列属于不同的类别,因此 paste 首先将第 1 行的两个元素转换为数字,然后再转换为字符。1as.numericpaste(df[1, ])

当您想连接两列时,您首先需要将第一行转换为字符:

df[, 1] <- as.character(df[, 1])
paste(df[1,], collapse = "")

正如@sebastian-c 指出的那样,您也可以stringsAsFactors = FALSE在创建data.frame 时使用,然后您可以省略该as.character()步骤。

于 2012-12-19T01:28:41.200 回答
1

如果你想开始

df <- data.frame(letters = LETTERS[1:5], numbers = 1:5, stringsAsFactors=TRUE)

..那么没有关于 df$letters任何给定函数将如何解释的一般规则。它是建模函数的一个因素,一些是字符,另一些是整数。即使是相同的函数(例如 paste)也可能会根据您的使用方式对它进行不同的解释:

paste(df[1,], collapse="") # "11"
apply(df, 1, paste, collapse="") # "A1" "B2" "C3" "D4" "E5"

它没有任何逻辑,只是一旦你了解了每个函数的内部结构,它可能就会有意义。

当参数转换为向量时,因子似乎被转换为整数(如您所知,数据帧是等长向量的列表,因此数据帧的第一行也是一个列表,并且当它被强制为一个向量,会发生这样的事情:)

df[1,]
#    letters numbers
# 1       A       1
unlist(df[1,])
# letters numbers 
#  1       1 

我不知道apply它是如何实现的(即,因子由字符值表示)——如果您有兴趣,请查看它的源代码。但是,知道您可以信任(在这个特定的意义上)apply(在这个特定的场合)可能会很有用。更一般地说,以合理的格式存储每条数据是有用的,包括将字符串存储为字符串,即使用stringsAsFactors=FALSE.

顺便说一句,每本介绍性的 R 书都应该在副标题中包含这个想法。例如,我的退休计划是写“用 R,stringsAsFactors=FALSE 方式对数据渔业禅宗的一个(不是那么)温和的介绍”。

于 2018-01-19T09:36:48.597 回答