简体   繁体   中英

Remove columns from data frame if any row contains a specific string

I would like to remove columns which contain the string -- in any row.

Number  138 139 140 141 143 144 147 148 149 150 151 152 14  15  N…  
nm4804  A   B   --  A   B   A   A   --  A   A   A   A   A   --  A  
nm7574  B   A   A   A   A   A   A   A   A   A   A   A   A   --  A
nm8723  B   --  B   B   B   --  A   --  B   B   B   B   --  --  A
N…      B   A   A   A   A   B   A   --  A   A   B   --  --  --  A

I would like to count the -- frequency, if there is any column have more than 50% of -- in the columns, that column will be removed.

Desired result:

Number  138 140 141 143 147 149 150 151 N…  
nm4804  A   A   --    B A   A   A   A   A  
nm7574  B   A   A    A  A   A   A   A   A
nm8723  B   B   A    B  --    B  B  B   A
N…          B   A   A    A  A A A   B   A

Data (thanks bgoldst)

df <- data.frame(Number=c('nm4804','nm7574','nm8723','N…'),`138`=c('A','B','B','B'),`139`=c(
'B','A','--','A'),`140`=c('--','A','B','A'),`141`=c('A','A','B','A'),`143`=c('B','A','B','A'
),`144`=c('A','A','--','B'),`147`=c('A','A','A','A'),`148`=c('--','A','--','--'),`149`=c('A',
'A','B','A'),`150`=c('A','A','B','A'),`151`=c('A','A','B','B'),`152`=c('A','A','B','--'),
`14`=c('A','A','--','--'),`15`=c('--','--','--','--'),`N…`=c('A','A','A','A'),check.names=F,
stringsAsFactors=F);

Use colSums() :

df[,colSums(df=='--')==0]
##   Number 138 141 143 147 149 150 151 N…
## 1 nm4804   A   A   B   A   A   A   A  A
## 2 nm7574   B   A   A   A   A   A   A  A
## 3 nm8723   B   B   B   A   B   B   B  A
## 4     N…   B   A   A   A   A   A   B  A

We can also use Filter

Filter(function(x) !any(x=="--"), df1)
#    Number X138 X141 X143 X147 X149 X150 X151 N…
#1 nm4804    A    A    B    A    A    A    A  A
#2 nm7574    B    A    A    A    A    A    A  A
#3 nm8723    B    B    B    A    B    B    B  A
#4     N…    B    A    A    A    A    A    B  A

If we need to remove the columns with more than 50% of --

Filter(function(x) mean(x == '--') <= 0.5, df1)

NOTE: Based on the OP's example, all the columns will be retained here.

Since it is unclear in the question, I'm assuming that nm4804 and such are row names, and 138..152 are column names, not actual data. With that, I'm guessing that this is a character matrix. Your data:

dat <- structure(c("A", "B", "B", "B", "B", "A", "--", "A", "--", "A", 
"B", "A", "A", "A", "B", "A", "B", "A", "B", "A", "A", "A", "--", 
"B", "A", "A", "A", "A", "--", "A", "--", "--", "A", "A", "B", 
"A", "A", "A", "B", "A", "A", "A", "B", "B", "A", "A", "B", "--", 
"A", "A", "--", "--", "--", "--", "--", "--", "A", "A", "A", 
"A"), .Dim = c(4L, 15L), .Dimnames = list(c("nm4804", "nm7574", 
"nm8723", "N..."), c("138", "139", "140", "141", "142", "143", 
"144", "145", "146", "147", "148", "149", "150", "151", "152"
)))

Try this:

dat[,! apply(dat, 2, `%in%`, x = "--")]
#        138 141 142 144 146 147 148 152
# nm4804 "A" "A" "B" "A" "A" "A" "A" "A"
# nm7574 "B" "A" "A" "A" "A" "A" "A" "A"
# nm8723 "B" "B" "B" "A" "B" "B" "B" "A"
# N...   "B" "A" "A" "A" "A" "A" "B" "A"

Here is a proposal using dplyr using the 'dat' dataframe proposed by @r2evans

dat <- structure(c("A", "B", "B", "B", "B", "A", "--", "A", "--", "A", 
"B", "A", "A", "A", "B", "A", "B", "A", "B", "A", "A", "A", "--", 
"B", "A", "A", "A", "A", "--", "A", "--", "--", "A", "A", "B", 
"A", "A", "A", "B", "A", "A", "A", "B", "B", "A", "A", "B", "--", 
"A", "A", "--", "--", "--", "--", "--", "--", "A", "A", "A", 
"A"), .Dim = c(4L, 15L), .Dimnames = list(c("nm4804", "nm7574", 
"nm8723", "N..."), c("138", "139", "140", "141", "142", "143", 
"144", "145", "146", "147", "148", "149", "150", "151", "152"
)))

This enables to remove all columns containing more than 50% of '--'

dat %>% 
as.data.frame() %>% 
select_if(~!(sum(.=="--") / length(.) > 0.5))

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM