pandas 0.1.0 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 056b93d472f805d8d482c29957bd5d69f7dea651
4
- data.tar.gz: c8bca642cea838cae4ec9629ef999ed69cb9d0dd
2
+ SHA256:
3
+ metadata.gz: 952bd0798aaf70a04aad070946185ba24462c5ba88d68650d65c096bcb3a8e81
4
+ data.tar.gz: fb70cd2d1f07485ea94fbab52ed054be9d14cbe35948a297d5f011b60f9353cb
5
5
  SHA512:
6
- metadata.gz: a0da4e097cb7c4621094ac780068c6834d893b1a31b5897269cf9832c5f1aa6b824fb7c85fcda14b0d7baf5e3c6b4ece0036a111ca1eed62a8a7e4fc8f0df5e5
7
- data.tar.gz: c6df181b48f80c7618201549c1858ae531d840a01713d9b1adb47f1ddbae842a3c03e9996175af365ac00c2890ba88dd2d45fd394fdcd4c70f8e33073f1bf352
6
+ metadata.gz: d21e7f9c032f5efae82689ac111167bdc3f9db844748aa2b148261750d39f54a17f3ce5c1578121238ef0dc5af7d04564672a18525f3394157dea4ba0f60b73a
7
+ data.tar.gz: 15bfd63048f2cbbc2f602ad08626a2d2fe838cf026eeaaa583a27223e9255291bea113ae97d23286fbcd89c249b1effb65235b3b18b5620f99446f9eb723e97c
@@ -0,0 +1,69 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - master
7
+ pull_request:
8
+ types:
9
+ - opened
10
+ - synchronize
11
+ - reopened
12
+
13
+ jobs:
14
+ test:
15
+ name: ${{ matrix.os}} ${{ matrix.ruby }} ${{ matrix.python }}-${{ matrix.python_arch }}
16
+ runs-on: ${{ matrix.os }}
17
+
18
+ strategy:
19
+ fail-fast: false
20
+ matrix:
21
+ os:
22
+ - ubuntu-latest
23
+ - macos-latest
24
+ ruby:
25
+ - 3.0
26
+ - 2.7
27
+ - 2.6
28
+ - 2.5
29
+ - 2.4
30
+ - debug
31
+ python:
32
+ - 3.8.x
33
+ - 3.7.x
34
+ - 3.6.x
35
+ - 2.7.x
36
+ python_arch:
37
+ - x64
38
+
39
+ steps:
40
+ - uses: actions/checkout@v2
41
+ with:
42
+ fetch-depth: 1
43
+
44
+ - uses: ruby/setup-ruby@v1
45
+ with:
46
+ ruby-version: ${{ matrix.ruby }}
47
+
48
+ - uses: actions/setup-python@v1
49
+ with:
50
+ python-version: ${{ matrix.python }}
51
+ architecture: ${{ matrix.python_arch }}
52
+
53
+ - run: sudo apt-get install libsqlite3-dev
54
+ if: matrix.os == 'ubuntu-latest'
55
+
56
+ - run: brew install sqlite3
57
+ if: matrix.os == 'macos-latest'
58
+
59
+ - run: pip install -r requirements.txt
60
+
61
+ - run: gem install bundler
62
+ - run: bundle install
63
+
64
+ - run: bundle exec rake
65
+ env:
66
+ PYTHON: python
67
+
68
+ - run: rake build
69
+ - run: gem install pkg/*.gem
@@ -0,0 +1,45 @@
1
+ # The chenge history of Pandas wrapper for Ruby
2
+
3
+ ## 0.3.3
4
+
5
+ * Support array index in `Pandas::Series#[]`
6
+
7
+ * Add predicate methods for `Pandas::Index` and `Pandas::Series`
8
+
9
+ * Support closed-end string ranges in `Pandas::Series#[]`
10
+
11
+ * Support string array index in `Pandas::DataFrame#loc[]`
12
+
13
+ * Support array index in `Pandas::DataFrame#iloc[]`
14
+
15
+ ## 0.3.2
16
+
17
+ * Fix for pandas 1.0
18
+
19
+ ## 0.3.1
20
+
21
+ * Fix `Pandas.read_sql_table` for passing optional parameters such as `index_col`
22
+
23
+ ## 0.3.0
24
+
25
+ * Fix the module path of `DatetimeIndex` to support pandas < 0.20
26
+
27
+ Fixes #5
28
+
29
+ *Daniel Baark*
30
+
31
+ * Support to pass an AR model class to `read_sql_table` instead of both `table_name` and `conn`
32
+
33
+ ## 0.2.0
34
+
35
+ * Support a connection of ActiveRecord in `read_sql_table` and `read_sql_query`
36
+
37
+ * Call `register_python_type_mapping` for all wrapper classes
38
+
39
+ * Support an array index in `DataFrame#[]`
40
+
41
+ * Fix `Pandas.options.display`
42
+
43
+ ## 0.1.0
44
+
45
+ * Define some wrapper classes
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Pandas wrapper for Ruby
2
2
 
3
+ [![Build Status](https://travis-ci.org/mrkn/pandas.rb.svg)](https://travis-ci.org/mrkn/pandas.rb)
4
+
3
5
  This library enables to directry call [pandas](http://pandas.pydata.org/) from Ruby language.
4
6
  This uses [pycall](https://github.com/mrkn/pycall).
5
7
 
@@ -1,19 +1,88 @@
1
1
  require "pandas/version"
2
- require "pycall"
2
+ require "numpy"
3
3
 
4
- Pandas = PyCall.import_module('pandas')
4
+ Pandas = PyCall.import_module("pandas")
5
5
  module Pandas
6
6
  VERSION = PANDAS_VERSION
7
7
  Object.send :remove_const, :PANDAS_VERSION
8
8
 
9
9
  DataFrame = self.core.frame.DataFrame
10
+ DataFrame.__send__ :register_python_type_mapping
11
+
10
12
  Series = self.core.series.Series
13
+ Series.__send__ :register_python_type_mapping
14
+
11
15
  IlocIndexer = self.core.indexing._iLocIndexer
16
+ IlocIndexer.__send__ :register_python_type_mapping
17
+
12
18
  LocIndexer = self.core.indexing._LocIndexer
13
- IXIndexer = self.core.indexing._IXIndexer
14
- MultiIndex = self.core.indexing.MultiIndex
15
- DatetimeIndex = self.core.indexes.datetimes.DatetimeIndex
16
- Index = self.core.index.Index
19
+ LocIndexer.__send__ :register_python_type_mapping
20
+
21
+ if self.__version__ < "1.0"
22
+ IXIndexer = self.core.indexing._IXIndexer
23
+ IXIndexer.__send__ :register_python_type_mapping
24
+ end
25
+
26
+ if self.__version__ >= "1.0"
27
+ MultiIndex = self.core.indexes.multi.MultiIndex
28
+ else
29
+ MultiIndex = self.core.indexing.MultiIndex
30
+ end
31
+ MultiIndex.__send__ :register_python_type_mapping
32
+
33
+ DatetimeIndex = if self.__version__ >= "0.20"
34
+ self.core.indexes.datetimes.DatetimeIndex
35
+ else
36
+ self.tseries.index.DatetimeIndex
37
+ end
38
+ DatetimeIndex.__send__ :register_python_type_mapping
39
+
40
+ if self.__version__ >= "1.0"
41
+ Index = self.core.indexes.base.Index
42
+ else
43
+ Index = self.core.index.Index
44
+ end
45
+ Index.__send__ :register_python_type_mapping
46
+
17
47
  DataFrameGroupBy = self.core.groupby.DataFrameGroupBy
48
+ DataFrameGroupBy.__send__ :register_python_type_mapping
49
+
18
50
  SeriesGroupBy = self.core.groupby.SeriesGroupBy
51
+ SeriesGroupBy.__send__ :register_python_type_mapping
52
+
53
+ IO = self.io
54
+
55
+ def self.read_sql_table(table_name, conn=nil, *args, **kwargs)
56
+ if conn.nil? && IO.is_activerecord_model?(table_name)
57
+ unless table_name.table_name
58
+ raise ArgumentError, "The given model does not have its table_name"
59
+ end
60
+ table_name, conn = table_name.table_name, table_name.connection
61
+ end
62
+
63
+ unless conn
64
+ raise ArgumentError, "wrong number of arguments (given 1, expected 2+)"
65
+ end
66
+
67
+ if IO.is_activerecord_datasource?(conn)
68
+ require 'pandas/io/active_record'
69
+ return IO::Helpers.read_sql_table_from_active_record(table_name, conn, *args, **kwargs)
70
+ end
71
+ super
72
+ end
73
+
74
+ def self.read_sql_query(query, conn, *args, **kwargs)
75
+ if IO.is_activerecord_datasource?(conn)
76
+ require 'pandas/io/active_record'
77
+ return IO::Helpers.read_sql_query_from_active_record(query, conn, *args, **kwargs)
78
+ end
79
+ super
80
+ end
81
+
82
+ require 'pandas/data_frame'
83
+ require 'pandas/index'
84
+ require 'pandas/io'
85
+ require 'pandas/loc_indexer'
86
+ require 'pandas/options'
87
+ require 'pandas/series'
19
88
  end
@@ -0,0 +1,10 @@
1
+ require 'pandas'
2
+
3
+ module Pandas
4
+ class DataFrame
5
+ def [](key)
6
+ key = PyCall::List.new(key) if key.is_a?(Array)
7
+ super
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ require 'pandas'
2
+
3
+ module Pandas
4
+ class Index
5
+ def monotonic?
6
+ is_monotonic
7
+ end
8
+
9
+ def monotonic_decreasing?
10
+ is_monotonic_decreasing
11
+ end
12
+
13
+ def monotonic_increasing?
14
+ is_monotonic_increasing
15
+ end
16
+
17
+ def unique?
18
+ is_unique
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ require 'pandas'
2
+
3
+ module Pandas
4
+ module IO
5
+ def self.is_activerecord_model?(obj)
6
+ return false unless defined?(::ActiveRecord)
7
+ return true if obj.is_a?(Class) && obj < ActiveRecord::Base
8
+ false
9
+ end
10
+
11
+ def self.is_activerecord_datasource?(obj)
12
+ return false unless defined?(::ActiveRecord)
13
+ return true if obj.is_a?(::ActiveRecord::ConnectionAdapters::AbstractAdapter)
14
+ false
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,101 @@
1
+ require 'pandas'
2
+ require 'active_record'
3
+
4
+ module Pandas
5
+ module IO
6
+ module Helpers
7
+ module_function
8
+
9
+ def read_sql_table_from_active_record(table_name, conn, *args)
10
+ case conn
11
+ when ActiveRecord::ConnectionAdapters::AbstractAdapter
12
+ read_sql_table_from_active_record_connection(table_name, conn, *args)
13
+ else
14
+ raise TypeError, "unexpected type of argument #{conn.class}"
15
+ end
16
+ end
17
+
18
+ def read_sql_query_from_active_record(query, conn, *args)
19
+ case conn
20
+ when ActiveRecord::ConnectionAdapters::AbstractAdapter
21
+ read_sql_query_from_active_record_connection(query, conn, *args)
22
+ else
23
+ raise TypeError, "unexpected type of argument #{conn.class}"
24
+ end
25
+ end
26
+
27
+ def read_sql_table_from_active_record_connection(table_name, conn, *args)
28
+ args = parse_read_sql_table_args(*args)
29
+ index_col, coerce_float, parse_dates, columns, schema, chunksize = *args
30
+ if columns
31
+ table_columns = conn.columns(table_name)
32
+ column_names = columns.select {|c| table_columns.include?(c) }.map do |c|
33
+ conn.quote_column_name(c.to_s)
34
+ end
35
+ else
36
+ column_names = '*'
37
+ end
38
+ query = <<-SQL
39
+ select #{column_names} from #{conn.quote_table_name(table_name)};
40
+ SQL
41
+ # TODO: chunksize
42
+ result = conn.exec_query(query, 'pandas_sql')
43
+ data_frame_from_query_result(result, index_col, coerce_float, parse_dates)
44
+ end
45
+
46
+ def read_sql_query_from_active_record_connection(query, conn, *args)
47
+ args = parse_read_sql_query_args(*args)
48
+ index_col, coerce_float, parse_dates, chunksize = *args
49
+ # TODO: chunksize
50
+ result = conn.exec_query(query, 'pandas_sql')
51
+ data_frame_from_query_result(result, index_col, coerce_float, parse_dates)
52
+ end
53
+
54
+ def data_frame_from_query_result(result, index_col, coerce_float, parse_dates)
55
+ records = result.map {|row| row.values }
56
+ df = Pandas::DataFrame.from_records(
57
+ records,
58
+ columns: result.columns,
59
+ coerce_float: coerce_float
60
+ )
61
+ # TODO: self.sql._harmonize_columns(parse_dates: parse_dates)
62
+ df.set_index(index_col, inplace: true) if index_col
63
+ df
64
+ end
65
+
66
+ def parse_read_sql_table_args(*args)
67
+ kwargs = args.pop if args.last.is_a? Hash
68
+ if kwargs
69
+ names = [:index_col, :coerce_float, :parse_dates, :columns, :schema, :chunksize]
70
+ names.each_with_index do |name, index|
71
+ if kwargs.has_key? name
72
+ if args[index]
73
+ warn "#{name} is given as both positional and keyword arguments"
74
+ else
75
+ args[index] = kwargs[name]
76
+ end
77
+ end
78
+ end
79
+ end
80
+ args
81
+ end
82
+
83
+ def parse_read_sql_query_args(*args)
84
+ kwargs = args.pop if args.last.is_a? Hash
85
+ if kwargs
86
+ names = [:index_col, :coerce_float, :parse_dates, :chunksize]
87
+ names.each_with_index do |name, index|
88
+ if kwargs.has_key? name
89
+ if args[index]
90
+ warn "#{name} is given as both positional and keyword arguments"
91
+ else
92
+ args[index] = kwargs[name]
93
+ end
94
+ end
95
+ end
96
+ end
97
+ args
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,25 @@
1
+ require 'pandas'
2
+
3
+ module Pandas
4
+ class LocIndexer
5
+ def [](*keys)
6
+ for i in 0...keys.length
7
+ if keys[i].is_a? Array
8
+ keys[i] = PyCall::List.new(keys[i])
9
+ end
10
+ end
11
+ super
12
+ end
13
+ end
14
+
15
+ class IlocIndexer
16
+ def [](*keys)
17
+ for i in 0...keys.length
18
+ if keys[i].is_a? Array
19
+ keys[i] = PyCall::List.new(keys[i])
20
+ end
21
+ end
22
+ super
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,17 @@
1
+ module Pandas
2
+ module OptionsHelper
3
+ module_function
4
+
5
+ def setup_options(options)
6
+ PyCall::LibPython::Helpers.define_wrapper_method(options, :display)
7
+ options
8
+ end
9
+ end
10
+
11
+ def self.options
12
+ @options ||= begin
13
+ o = PyCall::LibPython::Helpers.getattr(__pyptr__, :options)
14
+ OptionsHelper.setup_options(o)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,36 @@
1
+ require 'pandas'
2
+
3
+ module Pandas
4
+ class Series
5
+ def [](*key)
6
+ if key.length == 1
7
+ case key[0]
8
+ when Array
9
+ key[0] = PyCall::List.new(key[0])
10
+ when Range
11
+ case key[0].begin
12
+ when String
13
+ key[0] = key[0].begin ... key[0].end # force exclude-end
14
+ end
15
+ end
16
+ end
17
+ super
18
+ end
19
+
20
+ def monotonic?
21
+ is_monotonic
22
+ end
23
+
24
+ def monotonic_decreasing?
25
+ is_monotonic_decreasing
26
+ end
27
+
28
+ def monotonic_increasing?
29
+ is_monotonic_increasing
30
+ end
31
+
32
+ def unique?
33
+ is_unique
34
+ end
35
+ end
36
+ end
@@ -1 +1 @@
1
- PANDAS_VERSION = "0.1.0"
1
+ PANDAS_VERSION = "0.3.3"
@@ -22,8 +22,11 @@ Gem::Specification.new do |spec|
22
22
  spec.require_paths = ["lib"]
23
23
 
24
24
  spec.add_dependency "pycall", ">= 1.0.0"
25
+ spec.add_dependency "numpy"
25
26
 
26
- spec.add_development_dependency "bundler", "~> 1.15"
27
- spec.add_development_dependency "rake", "~> 10.0"
28
- spec.add_development_dependency "rspec", "~> 3.0"
27
+ spec.add_development_dependency "bundler", ">= 1.17.2"
28
+ spec.add_development_dependency "rake"
29
+ spec.add_development_dependency "rspec"
30
+ spec.add_development_dependency "activerecord", ">= 4.2"
31
+ spec.add_development_dependency "sqlite3"
29
32
  end
@@ -0,0 +1,2 @@
1
+ pandas
2
+ sqlalchemy
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pandas
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kenta Murata
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-09-07 00:00:00.000000000 Z
11
+ date: 2021-01-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: pycall
@@ -24,48 +24,90 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 1.0.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: numpy
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
- - - "~>"
45
+ - - ">="
32
46
  - !ruby/object:Gem::Version
33
- version: '1.15'
47
+ version: 1.17.2
34
48
  type: :development
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
- - - "~>"
52
+ - - ">="
39
53
  - !ruby/object:Gem::Version
40
- version: '1.15'
54
+ version: 1.17.2
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rake
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
- - - "~>"
59
+ - - ">="
46
60
  - !ruby/object:Gem::Version
47
- version: '10.0'
61
+ version: '0'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
- - - "~>"
66
+ - - ">="
53
67
  - !ruby/object:Gem::Version
54
- version: '10.0'
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rspec
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
- - - "~>"
73
+ - - ">="
60
74
  - !ruby/object:Gem::Version
61
- version: '3.0'
75
+ version: '0'
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
- - - "~>"
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: activerecord
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '4.2'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '4.2'
97
+ - !ruby/object:Gem::Dependency
98
+ name: sqlite3
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
67
109
  - !ruby/object:Gem::Version
68
- version: '3.0'
110
+ version: '0'
69
111
  description: Pandas wrapper for Ruby
70
112
  email:
71
113
  - mrkn@mrkn.jp
@@ -73,9 +115,10 @@ executables: []
73
115
  extensions: []
74
116
  extra_rdoc_files: []
75
117
  files:
118
+ - ".github/workflows/ci.yml"
76
119
  - ".gitignore"
77
120
  - ".rspec"
78
- - ".travis.yml"
121
+ - CHANGES.md
79
122
  - Gemfile
80
123
  - LICENSE.txt
81
124
  - README.md
@@ -84,13 +127,21 @@ files:
84
127
  - bin/setup
85
128
  - data/titanic.csv
86
129
  - lib/pandas.rb
130
+ - lib/pandas/data_frame.rb
131
+ - lib/pandas/index.rb
132
+ - lib/pandas/io.rb
133
+ - lib/pandas/io/active_record.rb
134
+ - lib/pandas/loc_indexer.rb
135
+ - lib/pandas/options.rb
136
+ - lib/pandas/series.rb
87
137
  - lib/pandas/version.rb
88
138
  - pandas.gemspec
139
+ - requirements.txt
89
140
  homepage: https://github.com/mrkn/pandas.rb
90
141
  licenses:
91
142
  - MIT
92
143
  metadata: {}
93
- post_install_message:
144
+ post_install_message:
94
145
  rdoc_options: []
95
146
  require_paths:
96
147
  - lib
@@ -105,9 +156,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
156
  - !ruby/object:Gem::Version
106
157
  version: '0'
107
158
  requirements: []
108
- rubyforge_project:
109
- rubygems_version: 2.6.12
110
- signing_key:
159
+ rubygems_version: 3.2.3
160
+ signing_key:
111
161
  specification_version: 4
112
162
  summary: Pandas wrapper for Ruby
113
163
  test_files: []
@@ -1,5 +0,0 @@
1
- sudo: false
2
- language: ruby
3
- rvm:
4
- - 2.4.1
5
- before_install: gem install bundler -v 1.15.4