How to delete the columns of a dataframe that have only positive values in Julia?

Viewed 684

I'm working with Julia and trying to edit a DataFrame. My objective is to keep the columns in which at least one value is <=0.

For example, using the code

using DataFrames

data = Dict("A"=>[1,7,2], 
    "B"=>[3,-9,-3], 
    "C"=>[3,0,6], 
    "D"=>[8,4,2], 
    "E"=>[4,3,-4])

df = DataFrame(data)

I get the following result

enter image description here

And I'm trying to transform it into the following DataFrame

enter image description here

There are some options to remove rows based on conditions, but I haven't found any that does the same to columns.

Does anyone know how to do this in a simple way?

3 Answers

There are many ways to do this as DataFrames offers the full flexibility of Julia base, but a simple and in my opinion clear way is:

julia> data[!, any.(<=(0), eachcol(data))]
3×2 DataFrame
 Row │ B      E     
     │ Int64  Int64 
─────┼──────────────
   1 │     3      4
   2 │    -9      3
   3 │    -3     -4

Let me also add that you don't have to create a Dict to create a DataFrame, the constructor works fine with String / Vector pairs:

julia> data = DataFrame("A"=>[1,7,2], 
           "B"=>[3,-9,-3], 
           "C"=>[3,0,6], 
           "D"=>[8,4,2], 
           "E"=>[4,3,-4])
3×5 DataFrame
 Row │ A      B      C      D      E     
     │ Int64  Int64  Int64  Int64  Int64 
─────┼───────────────────────────────────
   1 │     1      3      3      8      4
   2 │     7     -9      0      4      3
   3 │     2     -3      6      2     -4

Here is how I would do it,

using DataFrames
data = DataFrame(A = [1, 7, 2], B = [3, -9, -3], C = [3, 0, 6], D = [8, 4, 2], E = [4, 3, -4])

With array comprehension

data[!, [ any(x -> x ≤ 0, col) for col in eachcol(data) ]]

or with map

data[!, map(col -> any(x -> x ≤ 0, col), eachcol(data))]

or with broadcasting as in Nils' answer

data[!, any.(≤(0), eachcol(data))]

This is a bit janky, but you can find whether each element is <= 0 and then find the maximum value within each column to find cols that contain such an element. From there, you can filter by standard indexing:

julia> relevant_cols = maximum.(eachcol(df .<= 0))
5-element BitArray{1}:
 0
 1
 1
 0
 1

julia> reduced_df = df[!,relevant_cols]
3×3 DataFrame
│ Row │ B     │ C     │ E     │
│     │ Int64 │ Int64 │ Int64 │
├─────┼───────┼───────┼───────┤
│ 1   │ 3     │ 3     │ 4     │
│ 2   │ -9    │ 0     │ 3     │
│ 3   │ -3    │ 6     │ -4    │

EDIT: Made the answer compatible with current versions of DataFrames and removed previously suggested filter! command as a potential solution, as it's row-based not column-based.

Related