我有一个数据框,我试图循环遍历该数据框以识别那些包含特殊字符或全部大写字母的列。
我尝试了一些方法,但没有任何方法可以捕获循环中的列名称。
data = data.frame(one=c(1,3,5,1,3,5,1,3,5,1,3,5), two=c(1,3,5,1,3,5,1,3,5,1,3,5),
thr=c("A","B","D","E","F","G","H","I","J","H","I","J"),
fou=c("A","B","D","A","B","D","A","B","D","A","B","D"),
fiv=c(1,3,5,1,3,5,1,3,5,1,3,5),
six=c("A","B","D","E","F","G","H","I","J","H","I","J"),
sev=c("A","B","D","A","B","D","A","B","D","A","B","D"),
eig=c("A","B","D","A","B","D","A","B","D","A","B","D"),
nin=c(1.24,3.52,5.33,1.44,3.11,5.33,1.55,3.66,5.33,1.32,3.54,5.77),
ten=c(1:12),
ele=rep(1,12),
twe=c(1,2,1,2,1,2,1,2,1,2,1,2),
thir=c("THiS","THAT34","T(&*(", "!!!","@$#","$Q%J","who","THIS","this","this","this","this"),
stringsAsFactors = FALSE)
data
colls <- c()
spec=c("$","%","&")
for( col in names(data) ) {
if( length(strings[stringr::str_detect(data[,col], spec)]) >= 1 ){
print("HORRAY")
colls <- c(collls, col)
}
else print ("NOOOOOOOOOO")
}
for( col in names(data) ) {
if( any(data[,col]) %in% spec ){
print("HORRAY")
colls <- c(collls, col)
}
else print ("NOOOOOOOOOO")
}
任何人都可以阐明解决此问题的好方法吗?
编辑:
最终目标是拥有一个具有满足该条件的列名称的向量。抱歉我的问题很糟糕,但希望这对我想做的事情有所帮助
最佳答案
我会使用 grep() 来搜索您感兴趣的模式。请参阅 here 。
[:upper:]
匹配任何大写字母。
将其与 anchor (^,$) 组合并匹配一次或多次 (+) 会得到 ^[[:upper:]]+$
并且应该只匹配完全大写的条目。
以下内容将匹配您的玩具数据集中的特殊字符(但不保证匹配您真实数据集中的所有特殊字符,即换页符、回车符)
[:punct:]
#匹配标点符号 - ! "# $ % & ' ( ) * + , - ./: ; < = > ? @ [\] ^ _ ` { | } ~.
请注意,您可以手动定义特殊字符,而不是使用 [:punct:]
。
我们可以在数据集的第一行上尝试生成的代码:
#Using grepl() rather than grep() so that we return a list of logical values.
grepl(x= data[1,], pattern = "^[[:upper:]]+$|[[:punct:]]")
[1] FALSE FALSE TRUE TRUE FALSE TRUE TRUE TRUE TRUE FALSE FALSE FALSE FALSE
这为我们提供了预期的响应,但第九列的值除外,该列的值为 1.24。这里小数点被识别为标点符号并被标记为匹配。
我们可以添加一个“否定先行断言” - (?!\\.)
- 在测试句点是否为标点符号之前,将其从考虑中删除。请注意,我们使用\来转义句点。
grepl(x= data[1,], perl = TRUE, pattern = "(?!\\.)(^[[:upper:]]+$|[[:punct:]])")
[1] FALSE FALSE TRUE TRUE FALSE TRUE TRUE TRUE FALSE FALSE FALSE FALSE TRUE
这会返回更好的响应 - 它现在不再匹配小数位。注意:这可能不是您想要的,因为此模式也不会匹配字符字段中的任何句号。您需要进一步完善该模式。
我不会使用“for 循环”在数据帧中的每一行重复此代码,而是使用矢量化,这“更像 R”。
为此,我们必须将脚本转换为我们将使用 apply() 调用的函数
myFunction <- function(x){
matches <- grepl(x= x, perl = TRUE, pattern = "(?!\\.)(^[[:upper:]]+$|[[:punct:]])")
#Given a set of logical vectors 'matches', is at least one of the values true? using any()
return(any(matches))
}
apply(X = data, 1, myFunction)
上面的 1 指示 apply() 跨行而不是列重复。
[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
在示例数据集中,所有行都有一个包含特殊字符或全大写字母的字符串的条目。这并不奇怪,因为示例数据集中的许多列都是单个大写字母的列表。
如果您只是对第十三列中的哪些值符合规定的条件感兴趣,您可以使用:
matches <- grepl(x= data$thir, perl = TRUE, pattern = "(?!\\.)(^[[:upper:]]+$|[[:punct:]])")
matches
[1] FALSE FALSE TRUE TRUE TRUE TRUE FALSE TRUE FALSE FALSE FALSE FALSE
要在匹配行上对数据框进行子集化:
data[matches,]
one two thr fou fiv six sev eig nin ten ele twe thir
3 5 5 D D 5 D D D 5.33 3 1 1 T(&*(
4 1 1 E A 1 E A A 1.44 4 1 2 !!!
5 3 3 F B 3 F B B 3.11 5 1 1 @$#
6 5 5 G D 5 G D D 5.33 6 1 2 $Q%J
8 3 3 I B 3 I B B 3.66 8 1 2 THIS
要在不匹配的行上对数据框进行子集化:
data[!matches,]
one two thr fou fiv six sev eig nin ten ele twe thir
1 1 1 A A 1 A A A 1.24 1 1 1 THiS
2 3 3 B B 3 B B B 3.52 2 1 2 THAT34
7 1 1 H A 1 H A A 1.55 7 1 1 who
9 5 5 J D 5 J D D 5.33 9 1 1 this
10 1 1 H A 1 H A A 1.32 10 1 2 this
11 3 3 I B 3 I B B 3.54 11 1 1 this
12 5 5 J D 5 J D D 5.77 12 1 2 this
请注意,使用的正则表达式与 THAT34 不匹配,因为它不完全由大写字母组成,末尾有数字 34。
编辑:
要获取列名称列表,用于标识满足编辑条件的列,请使用上面描述的 myFunction
:
colnames(data)[apply(X = data, 2, myFunction)]
"thr" "fou" "six" "sev" "eig" "thir"
apply() 中的数字从 1 更改为 2,以便跨列而不是行重复。我们将 apply() 的输出(逻辑匹配列表(TRUE 或 FALSE))传递给 colnames(data) - 这通过子集设置返回匹配的列名称。
关于regex - 抓取带有特殊字符和大写字母的列,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36851369/