Evan
Evan

Reputation: 1499

How to conditionally delete rows in R?

I have a date.frame that looks like:

        SNP              CLST A1 A2       FRQ IMP     POS CHR BVAL
1   rs2803291            Brahui  C  T  0.660000   0 1882185   1  878
2   rs2803291           Balochi  C  T  0.750000   0 1882185   1  878
3   rs2803291            Hazara  C  T  0.772727   0 1882185   1  878
4   rs2803291           Makrani  C  T  0.620000   0 1882185   1  878
5   rs2803291            Sindhi  C  T  0.770833   0 1882185   1  878
6   rs2803291            Pathan  C  T  0.681818   0 1882185   1  878
53  rs12060022           Brahui  T  C 0.0600000   1 3108186   1  982
54  rs12060022          Balochi  T  C 0.0416667   1 3108186   1  982
55  rs12060022           Hazara  T  C 0.0000000   1 3108186   1  982
56  rs12060022          Makrani  T  C 0.0200000   1 3108186   1  982
57  rs12060022           Sindhi  T  C 0.0625000   1 3108186   1  982
58  rs12060022           Pathan  T  C 1           1 3108186   1  982
105   rs870171           Brahui  T  G 0.2200000   0 3332664   1  976
106   rs870171          Balochi  T  G 0.3333330   0 3332664   1  976
107   rs870171           Hazara  T  G 1           0 3332664   1  976
108   rs870171          Makrani  T  G 1           0 3332664   1  976
109   rs870171           Sindhi  T  G 0.2083330   0 3332664   1  976
110   rs870171           Pathan  T  G 1           0 3332664   1  976
157  rs4282783           Brahui  G  T 1           1 4090545   1  992
158  rs4282783          Balochi  G  T 1           1 4090545   1  992
159  rs4282783           Hazara  G  T 1           1 4090545   1  992
160  rs4282783          Makrani  G  T 1           1 4090545   1  992
161  rs4282783           Sindhi  G  T 1           1 4090545   1  992
162  rs4282783           Pathan  G  T 1           1 4090545   1  992

I would like to delete all rows where every single line for the given SNP has a value of 1 in the FRQ column. For example, every rs4282783 has a value of 1 in the FRQ column so I would like to delete all of those rows. But I don't want to delete row 58 for example which has a 1 value in FRQ. Does anyone have any advice?

Upvotes: 0

Views: 184

Answers (4)

akrun
akrun

Reputation: 886948

Here is a data.table based approach. Convert the 'data.frame' to 'data.table' (setDT(df)), grouped by 'SNP', if not (!) all the elements in 'FRQ' is 1, then get the Subset of Data.table.

library(data.table)
setDT(df)[, if(!(all(FRQ==1))) .SD , by = SNP]

Or a general approach if I may guess that the OP meant to delete all SNPs having only a single "FRQ", then we can use uniqueN to find the number of unique elements and use in the if condition to keep only those having more than 1

setDT(df)[, if(uniqueN(FRQ) > 1) .SD , by = SNP]

Upvotes: 2

lmo
lmo

Reputation: 38500

Here is a base R method using subsetting and ave. ave constructs the group-level (SNP-level) maximum, which is used to subset the data by observation:

df[ave(df$FRQ, df$SNP, FUN=max) < 0.99999,]

        SNP    CLST A1 A2      FRQ IMP     POS CHR BVAL
1 rs2803291  Brahui  C  T 0.660000   0 1882185   1  878
2 rs2803291 Balochi  C  T 0.750000   0 1882185   1  878
3 rs2803291  Hazara  C  T 0.772727   0 1882185   1  878
4 rs2803291 Makrani  C  T 0.620000   0 1882185   1  878
5 rs2803291  Sindhi  C  T 0.770833   0 1882185   1  878
6 rs2803291  Pathan  C  T 0.681818   0 1882185   1  878

Note that I used 0.99999 rather than 1 in order to avoid or reduce numerical imprecision issues.

data

df <- read.table(header=T, text="SNP  CLST A1 A2   FRQ IMP  POS CHR BVAL
1   rs2803291            Brahui  C  T  0.660000   0 1882185   1  878
2   rs2803291           Balochi  C  T  0.750000   0 1882185   1  878
3   rs2803291            Hazara  C  T  0.772727   0 1882185   1  878
4   rs2803291           Makrani  C  T  0.620000   0 1882185   1  878
5   rs2803291            Sindhi  C  T  0.770833   0 1882185   1  878
6   rs2803291            Pathan  C  T  0.681818   0 1882185   1  878
53  rs12060022           Brahui  T  C 0.0600000   1 3108186   1  982
54  rs12060022          Balochi  T  C 0.0416667   1 3108186   1  982
55  rs12060022           Hazara  T  C 0.0000000   1 3108186   1  982
56  rs12060022          Makrani  T  C 0.0200000   1 3108186   1  982
57  rs12060022           Sindhi  T  C 0.0625000   1 3108186   1  982
58  rs12060022           Pathan  T  C 1           1 3108186   1  982
105   rs870171           Brahui  T  G 0.2200000   0 3332664   1  976
106   rs870171          Balochi  T  G 0.3333330   0 3332664   1  976
107   rs870171           Hazara  T  G 1           0 3332664   1  976
108   rs870171          Makrani  T  G 1           0 3332664   1  976
109   rs870171           Sindhi  T  G 0.2083330   0 3332664   1  976
110   rs870171           Pathan  T  G 1           0 3332664   1  976
157  rs4282783           Brahui  G  T 1           1 4090545   1  992
158  rs4282783          Balochi  G  T 1           1 4090545   1  992
159  rs4282783           Hazara  G  T 1           1 4090545   1  992
160  rs4282783          Makrani  G  T 1           1 4090545   1  992
161  rs4282783           Sindhi  G  T 1           1 4090545   1  992
162  rs4282783           Pathan  G  T 1           1 4090545   1  992")

Upvotes: 2

timcdlucas
timcdlucas

Reputation: 1364

@imo's answer is neater but as I've done mine I'll add it. To my mind the logic is slightly clearer.

# which SNPs are always 1
# For each SNP value, take the rows with that SNP, and test if all FRQ values are 1
rmSNPs <- sapply(unique(dd$SNP), function(x) all(dd$FRQ[dd$SNP == x] == 1))

# new data is old data minus row where dd$SNP is not one of those found above
newdata <- dd[dd$SNP != unique(dd$SNP)[rmSNPs], ]

Upvotes: 2

Steven Beaupr&#233;
Steven Beaupr&#233;

Reputation: 21621

To remove SNP where all values of FRQ is equal to 1, you could try:

library(dplyr)
df %>%
  group_by(SNP) %>%
  filter(!all(FRQ == 1))

Which gives:

#         SNP    CLST     A1     A2       FRQ   IMP     POS   CHR  BVAL
#       <fctr>  <fctr> <fctr> <fctr>     <dbl> <int>   <int> <int> <int>
#1   rs2803291  Brahui      C      T 0.6600000     0 1882185     1   878
#2   rs2803291 Balochi      C      T 0.7500000     0 1882185     1   878
#3   rs2803291  Hazara      C      T 0.7727270     0 1882185     1   878
#4   rs2803291 Makrani      C      T 0.6200000     0 1882185     1   878
#5   rs2803291  Sindhi      C      T 0.7708330     0 1882185     1   878
#6   rs2803291  Pathan      C      T 0.6818180     0 1882185     1   878
#7  rs12060022  Brahui      T      C 0.0600000     1 3108186     1   982
#8  rs12060022 Balochi      T      C 0.0416667     1 3108186     1   982
#9  rs12060022  Hazara      T      C 0.0000000     1 3108186     1   982
#10 rs12060022 Makrani      T      C 0.0200000     1 3108186     1   982
#11 rs12060022  Sindhi      T      C 0.0625000     1 3108186     1   982
#12 rs12060022  Pathan      T      C 1.0000000     1 3108186     1   982
#13   rs870171  Brahui      T      G 0.2200000     0 3332664     1   976
#14   rs870171 Balochi      T      G 0.3333330     0 3332664     1   976
#15   rs870171  Hazara      T      G 1.0000000     0 3332664     1   976
#16   rs870171 Makrani      T      G 1.0000000     0 3332664     1   976
#17   rs870171  Sindhi      T      G 0.2083330     0 3332664     1   976
#18   rs870171  Pathan      T      G 1.0000000     0 3332664     1   976

Upvotes: 3

Related Questions