在 R 中,当从另一列中的分隔文本为列创建名称时,新列名称仅从第一行分配
In R when creating names for columns from delimited text in another column, new columns names are only assigned from the 1st row
使用 R 从另一列中的分隔文本创建列名称,新列的名称仅取自第一行,其余标记为 NA。即使他们分配了正确的值。
数据由有效的分号分隔值以及一列中的空值和 NULL 值组成。我正在尝试创建以每个有效分隔值命名的新列,并将值 1 分配给找到该列名称的行的新列。
例如
A B C E Domestic Glue_Sniffing NA NA NA NA NA NA NA
1 1 0 ;Domestic;;Domestic abuse;Glue Sniffing 7 1 NA NA NA NA NA NA NA NA
2 2 4 ;Drug;Abus; 8 NA NA 1 1 NA NA NA NA NA
3 3 6 ;Drug;Domestic Abuse;Domestic; 9 1 NA 1 NA NA NA NA NA NA
4 4 5 ;Alcohol;;Verbal; 5 NA NA NA NA 1 1 NA NA NA
5 5 7 ;Shinpads;Abus ; ; 6 NA NA NA 1 NA NA 1 NA NA
6 6 9 7 NA NA NA NA NA NA NA NA NA
7 7 12 ;Ail; 8 NA NA NA NA NA NA NA NA 1
8 8 10 7 NA NA NA NA NA NA NA NA NA
9 9 9 ; 8 NA NA NA NA NA NA NA NA NA
问题是它只取查询的第一行中的名字。
我将以下答案用作 template
我哪里错了?
代码与模板相同,但修改为向每个分隔元素添加“=1”,如下所示:
#Define a function to take vectors like c("A=1","B=2") and changed them into named vectors like c(A="1", B="2").
createNamedVectors <- function(x) {
a <- strsplit(x,"=")
setNames(sapply(a,'[',2), sapply(a,'[',1))
}
tmp.df<-data.frame(
A = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9),
B = c(0L, 4, 6, 5L, 7L, 9L, 12L, 10L, 9),
C = c(";Ailment;Drug;Abus;Domestic;Domestic abuse;Glue Sniffing",
";Drug;Abus;",
";Drug;Domestic Abuse;Domestic;",
";Alcohol;;Verbal;",
";Shinpads; ;",
"",
";Ail;",
" ",
";"),
D = c(";Vodka=2;Drug;Abus;",
";Drug;Abu;",
";Alcohol;Drug;Verbal;",
";Drug;Doms;",
";Shinpads;",
" ",
"",
";Ail;",
"New"),
E = c(7L, 8L, 9L, 5L, 6L, 7L, 8L, 7L, 8),
stringsAsFactors=T
)
DelimitedNamesOfNewCols <- str_replace_all(as.character(tmp.df$C),"Domestic [Aa]buse","Domestic")
DelimitedNamesOfNewCols <- str_replace_all(DelimitedNamesOfNewCols,";*[[:space:]]*;",";")
DelimitedNamesOfNewCols <- str_replace_all(DelimitedNamesOfNewCols,"^;","")
DelimitedNamesOfNewCols <- str_replace_all(DelimitedNamesOfNewCols,";","=1;")
DelimitedNamesOfNewCols <- str_replace_all(DelimitedNamesOfNewCols,"^[[:space:]]+","DUMMY=;")
DelimitedNamesOfNewCols <- str_replace_all(DelimitedNamesOfNewCols,"[[:space:]]+$","DUMMY=;")
DelimitedNamesOfNewCols <- str_replace_all(DelimitedNamesOfNewCols,"[[:space:]]","_")
DelimitedNamesOfNewCols <- str_replace_all(DelimitedNamesOfNewCols,"^$","DUMMY=;")
DelimitedNamesOfNewCols <- str_replace_all(DelimitedNamesOfNewCols,";$","")
ColsAndValsAsNamedVectors <-lapply(strsplit(DelimitedNamesOfNewCols,";"), createNamedVectors)
#Get list of all column names, then trim and remove NA and blanks
UniqueColumnNames <-unique(unlist(sapply(ColsAndValsAsNamedVectors, names)))
UniqueColumnNames <- stri_trim(UniqueColumnNames)
UniqueColumnNames <- UniqueColumnNames[!is.na(UniqueColumnNames)]
UniqueColumnNames <- UniqueColumnNames[stri_cmp_gt(UniqueColumnNames,"")]
#Extract data from all rows for every column
DataFromRowsForEachColumn <-do.call(rbind, lapply(ColsAndValsAsNamedVectors, '[', UniqueColumnNames))
#Convert everything to numeric
class(DataFromRowsForEachColumn)<-"numeric"
#Rejoin with original data.frame removing column 4
cbind(tmp.df[,-4], DataFromRowsForEachColumn)
运行并检查大量调试语句
显示名称和值已正确分配给所有条目,直到 return 来自以下语句
lapply(ColsAndValsAsNamedVectors, '[', UniqueColumnNames)
在语句
中找到
DataFromRowsForEachColumn <- do.call(rbind, lapply(ColsAndValsAsNamedVectors, '[', UniqueColumnNames))
但是在 DataFromRowsForEachColumn 中只有第一行的列名。
我是否需要重新开始,我是否犯了一个明显的错误,或者我是否缺少更优雅的解决方案?
感谢收到所有回复
很可能有更好的方法来执行此操作,但您的代码几乎可以正常工作,所以让我们开始吧。
正如你所说,在我们到达这里之前一切都很好
# problem line
DataFromRowsForEachColumn <-do.call(rbind, lapply(ColsAndValsAsNamedVectors, '[', UniqueColumnNames))
如果我们只是 运行 lapply
,我们可以看到它工作正常,但只有在每个列表元素中,只有找到的列才会被命名。 rbind
不会添加到名称中,它只会从第一个列表元素中获取名称。
lapply(ColsAndValsAsNamedVectors, '[', UniqueColumnNames)
# [[1]]
# Ailment Drug Abus Domestic Glue_Sniffing <NA> <NA> <NA> <NA> <NA>
# "1" "1" "1" "1" NA NA NA NA NA NA
#
# [[2]]
# <NA> Drug Abus <NA> <NA> <NA> <NA> <NA> <NA> <NA>
# NA "1" "1" NA NA NA NA NA NA NA
#
# [[3]]
# <NA> Drug <NA> Domestic <NA> <NA> <NA> <NA> <NA> <NA>
# NA "1" NA "1" NA NA NA NA NA NA
#
# [[4]]
# <NA> <NA> <NA> <NA> <NA> Alcohol Verbal <NA> <NA> <NA>
# NA NA NA NA NA "1" "1" NA NA NA
#
# [[5]]
# <NA> <NA> <NA> <NA> <NA> <NA> <NA> Shinpads <NA> <NA>
# NA NA NA NA NA NA NA "1" NA NA
简单的解决方法是只修复结果中的名称:
colnames(DataFromRowsForEachColumn) = UniqueColumnNames
添加该行,我想您会对最终结果感到满意。
其他评论:
我非常怀疑您的 stri_trim
行 - 在您的管道中似乎为时已晚。我认为您需要早点 trim(如果需要的话)。看起来你用 "^[[:space:]]+"
和 "[[:space:]]+$"
替换行来处理它。您可以将这 2 个替换为 str_trim
。但是,如果在到达唯一列名时仍然有空格,请在上游进行修复。
不确定我是否理解正确,但为了从 ;
分隔行创建新列,您可以使用神奇的 tidyverse
包:
library(tidyverse)
df %>%
separate_rows(C, sep = ';') %>%
filter (C != '') %>%
mutate(new = 1) %>%
spread(C, new)
这会产生
A B D E Abus Ail Ailment Alcohol Domestic Domestic abuse Domestic Abuse Drug Glue Sniffing Shinpads Verbal
1 1 0 ;Vodka=2;Drug;Abus; 7 NA 1 NA 1 NA 1 1 NA 1 1 NA NA
2 2 4 ;Drug;Abu; 8 NA 1 NA NA NA NA NA NA 1 NA NA NA
3 3 6 ;Alcohol;Drug;Verbal; 9 NA NA NA NA NA 1 NA 1 1 NA NA NA
4 4 5 ;Drug;Doms; 5 NA NA NA NA 1 NA NA NA NA NA NA 1
5 5 7 ;Shinpads; 6 1 NA NA NA NA NA NA NA NA NA 1 NA
6 7 12 8 NA NA 1 NA NA NA NA NA NA NA NA NA
7 8 10 ;Ail; 7 1 NA NA NA NA NA NA NA NA NA NA NA
使用 R 从另一列中的分隔文本创建列名称,新列的名称仅取自第一行,其余标记为 NA。即使他们分配了正确的值。
数据由有效的分号分隔值以及一列中的空值和 NULL 值组成。我正在尝试创建以每个有效分隔值命名的新列,并将值 1 分配给找到该列名称的行的新列。
例如
A B C E Domestic Glue_Sniffing NA NA NA NA NA NA NA
1 1 0 ;Domestic;;Domestic abuse;Glue Sniffing 7 1 NA NA NA NA NA NA NA NA
2 2 4 ;Drug;Abus; 8 NA NA 1 1 NA NA NA NA NA
3 3 6 ;Drug;Domestic Abuse;Domestic; 9 1 NA 1 NA NA NA NA NA NA
4 4 5 ;Alcohol;;Verbal; 5 NA NA NA NA 1 1 NA NA NA
5 5 7 ;Shinpads;Abus ; ; 6 NA NA NA 1 NA NA 1 NA NA
6 6 9 7 NA NA NA NA NA NA NA NA NA
7 7 12 ;Ail; 8 NA NA NA NA NA NA NA NA 1
8 8 10 7 NA NA NA NA NA NA NA NA NA
9 9 9 ; 8 NA NA NA NA NA NA NA NA NA
问题是它只取查询的第一行中的名字。 我将以下答案用作 template
我哪里错了? 代码与模板相同,但修改为向每个分隔元素添加“=1”,如下所示:
#Define a function to take vectors like c("A=1","B=2") and changed them into named vectors like c(A="1", B="2").
createNamedVectors <- function(x) {
a <- strsplit(x,"=")
setNames(sapply(a,'[',2), sapply(a,'[',1))
}
tmp.df<-data.frame(
A = c(1L, 2L, 3L, 4L, 5L, 6L, 7L, 8L, 9),
B = c(0L, 4, 6, 5L, 7L, 9L, 12L, 10L, 9),
C = c(";Ailment;Drug;Abus;Domestic;Domestic abuse;Glue Sniffing",
";Drug;Abus;",
";Drug;Domestic Abuse;Domestic;",
";Alcohol;;Verbal;",
";Shinpads; ;",
"",
";Ail;",
" ",
";"),
D = c(";Vodka=2;Drug;Abus;",
";Drug;Abu;",
";Alcohol;Drug;Verbal;",
";Drug;Doms;",
";Shinpads;",
" ",
"",
";Ail;",
"New"),
E = c(7L, 8L, 9L, 5L, 6L, 7L, 8L, 7L, 8),
stringsAsFactors=T
)
DelimitedNamesOfNewCols <- str_replace_all(as.character(tmp.df$C),"Domestic [Aa]buse","Domestic")
DelimitedNamesOfNewCols <- str_replace_all(DelimitedNamesOfNewCols,";*[[:space:]]*;",";")
DelimitedNamesOfNewCols <- str_replace_all(DelimitedNamesOfNewCols,"^;","")
DelimitedNamesOfNewCols <- str_replace_all(DelimitedNamesOfNewCols,";","=1;")
DelimitedNamesOfNewCols <- str_replace_all(DelimitedNamesOfNewCols,"^[[:space:]]+","DUMMY=;")
DelimitedNamesOfNewCols <- str_replace_all(DelimitedNamesOfNewCols,"[[:space:]]+$","DUMMY=;")
DelimitedNamesOfNewCols <- str_replace_all(DelimitedNamesOfNewCols,"[[:space:]]","_")
DelimitedNamesOfNewCols <- str_replace_all(DelimitedNamesOfNewCols,"^$","DUMMY=;")
DelimitedNamesOfNewCols <- str_replace_all(DelimitedNamesOfNewCols,";$","")
ColsAndValsAsNamedVectors <-lapply(strsplit(DelimitedNamesOfNewCols,";"), createNamedVectors)
#Get list of all column names, then trim and remove NA and blanks
UniqueColumnNames <-unique(unlist(sapply(ColsAndValsAsNamedVectors, names)))
UniqueColumnNames <- stri_trim(UniqueColumnNames)
UniqueColumnNames <- UniqueColumnNames[!is.na(UniqueColumnNames)]
UniqueColumnNames <- UniqueColumnNames[stri_cmp_gt(UniqueColumnNames,"")]
#Extract data from all rows for every column
DataFromRowsForEachColumn <-do.call(rbind, lapply(ColsAndValsAsNamedVectors, '[', UniqueColumnNames))
#Convert everything to numeric
class(DataFromRowsForEachColumn)<-"numeric"
#Rejoin with original data.frame removing column 4
cbind(tmp.df[,-4], DataFromRowsForEachColumn)
运行并检查大量调试语句 显示名称和值已正确分配给所有条目,直到 return 来自以下语句
lapply(ColsAndValsAsNamedVectors, '[', UniqueColumnNames)
在语句
中找到DataFromRowsForEachColumn <- do.call(rbind, lapply(ColsAndValsAsNamedVectors, '[', UniqueColumnNames))
但是在 DataFromRowsForEachColumn 中只有第一行的列名。
我是否需要重新开始,我是否犯了一个明显的错误,或者我是否缺少更优雅的解决方案?
感谢收到所有回复
很可能有更好的方法来执行此操作,但您的代码几乎可以正常工作,所以让我们开始吧。
正如你所说,在我们到达这里之前一切都很好
# problem line
DataFromRowsForEachColumn <-do.call(rbind, lapply(ColsAndValsAsNamedVectors, '[', UniqueColumnNames))
如果我们只是 运行 lapply
,我们可以看到它工作正常,但只有在每个列表元素中,只有找到的列才会被命名。 rbind
不会添加到名称中,它只会从第一个列表元素中获取名称。
lapply(ColsAndValsAsNamedVectors, '[', UniqueColumnNames)
# [[1]]
# Ailment Drug Abus Domestic Glue_Sniffing <NA> <NA> <NA> <NA> <NA>
# "1" "1" "1" "1" NA NA NA NA NA NA
#
# [[2]]
# <NA> Drug Abus <NA> <NA> <NA> <NA> <NA> <NA> <NA>
# NA "1" "1" NA NA NA NA NA NA NA
#
# [[3]]
# <NA> Drug <NA> Domestic <NA> <NA> <NA> <NA> <NA> <NA>
# NA "1" NA "1" NA NA NA NA NA NA
#
# [[4]]
# <NA> <NA> <NA> <NA> <NA> Alcohol Verbal <NA> <NA> <NA>
# NA NA NA NA NA "1" "1" NA NA NA
#
# [[5]]
# <NA> <NA> <NA> <NA> <NA> <NA> <NA> Shinpads <NA> <NA>
# NA NA NA NA NA NA NA "1" NA NA
简单的解决方法是只修复结果中的名称:
colnames(DataFromRowsForEachColumn) = UniqueColumnNames
添加该行,我想您会对最终结果感到满意。
其他评论:
我非常怀疑您的 stri_trim
行 - 在您的管道中似乎为时已晚。我认为您需要早点 trim(如果需要的话)。看起来你用 "^[[:space:]]+"
和 "[[:space:]]+$"
替换行来处理它。您可以将这 2 个替换为 str_trim
。但是,如果在到达唯一列名时仍然有空格,请在上游进行修复。
不确定我是否理解正确,但为了从 ;
分隔行创建新列,您可以使用神奇的 tidyverse
包:
library(tidyverse)
df %>%
separate_rows(C, sep = ';') %>%
filter (C != '') %>%
mutate(new = 1) %>%
spread(C, new)
这会产生
A B D E Abus Ail Ailment Alcohol Domestic Domestic abuse Domestic Abuse Drug Glue Sniffing Shinpads Verbal
1 1 0 ;Vodka=2;Drug;Abus; 7 NA 1 NA 1 NA 1 1 NA 1 1 NA NA
2 2 4 ;Drug;Abu; 8 NA 1 NA NA NA NA NA NA 1 NA NA NA
3 3 6 ;Alcohol;Drug;Verbal; 9 NA NA NA NA NA 1 NA 1 1 NA NA NA
4 4 5 ;Drug;Doms; 5 NA NA NA NA 1 NA NA NA NA NA NA 1
5 5 7 ;Shinpads; 6 1 NA NA NA NA NA NA NA NA NA 1 NA
6 7 12 8 NA NA 1 NA NA NA NA NA NA NA NA NA
7 8 10 ;Ail; 7 1 NA NA NA NA NA NA NA NA NA NA NA