pyerrors.input.pandas

  1import gzip
  2import sqlite3
  3import warnings
  4from contextlib import closing
  5
  6import numpy as np
  7import pandas as pd
  8
  9from ..correlators import Corr
 10from ..obs import Obs
 11from .json import create_json_string, import_json_string
 12
 13
 14def to_sql(df, table_name, db, if_exists='fail', gz=True, **kwargs):
 15    """Write DataFrame including Obs or Corr valued columns to sqlite database.
 16
 17    Parameters
 18    ----------
 19    df : pandas.DataFrame
 20        Dataframe to be written to the database.
 21    table_name : str
 22        Name of the table in the database.
 23    db : str
 24        Path to the sqlite database.
 25    if exists : str
 26        How to behave if table already exists. Options 'fail', 'replace', 'append'.
 27    gz : bool
 28        If True the json strings are gzipped.
 29
 30    Returns
 31    -------
 32    None
 33    """
 34    se_df = _serialize_df(df, gz=gz)
 35    with closing(sqlite3.connect(db)) as con:
 36        se_df.to_sql(table_name, con=con, if_exists=if_exists, index=False, **kwargs)
 37
 38
 39def read_sql(sql, db, auto_gamma=False, **kwargs):
 40    """Execute SQL query on sqlite database and obtain DataFrame including Obs or Corr valued columns.
 41
 42    Parameters
 43    ----------
 44    sql : str
 45        SQL query to be executed.
 46    db : str
 47        Path to the sqlite database.
 48    auto_gamma : bool
 49        If True applies the gamma_method to all imported Obs objects with the default parameters for
 50        the error analysis. Default False.
 51
 52    Returns
 53    -------
 54    data : pandas.DataFrame
 55        Dataframe with the content of the sqlite database.
 56    """
 57    with closing(sqlite3.connect(db)) as con:
 58        extract_df = pd.read_sql(sql, con=con, **kwargs)
 59    return _deserialize_df(extract_df, auto_gamma=auto_gamma)
 60
 61
 62def dump_df(df, fname, gz=True):
 63    """Exports a pandas DataFrame containing Obs valued columns to a (gzipped) csv file.
 64
 65    Before making use of pandas to_csv functionality Obs objects are serialized via the standardized
 66    json format of pyerrors.
 67
 68    Parameters
 69    ----------
 70    df : pandas.DataFrame
 71        Dataframe to be dumped to a file.
 72    fname : str
 73        Filename of the output file.
 74    gz : bool
 75        If True, the output is a gzipped csv file. If False, the output is a csv file.
 76
 77    Returns
 78    -------
 79    None
 80    """
 81    for column in df:
 82        serialize = _need_to_serialize(df[column])
 83        if not serialize:
 84            if all(isinstance(entry, (int, np.integer, float, np.floating)) for entry in df[column]):
 85                if any([np.isnan(entry) for entry in df[column]]):
 86                    warnings.warn("nan value in column " + column + " will be replaced by None", UserWarning, stacklevel=2)
 87
 88    out = _serialize_df(df, gz=False)
 89
 90    if not fname.endswith('.csv'):
 91        fname += '.csv'
 92
 93    if gz is True:
 94        if not fname.endswith('.gz'):
 95            fname += '.gz'
 96        out.to_csv(fname, index=False, compression='gzip')
 97    else:
 98        out.to_csv(fname, index=False)
 99
100
101def load_df(fname, auto_gamma=False, gz=True):
102    """Imports a pandas DataFrame from a csv.(gz) file in which Obs objects are serialized as json strings.
103
104    Parameters
105    ----------
106    fname : str
107        Filename of the input file.
108    auto_gamma : bool
109        If True applies the gamma_method to all imported Obs objects with the default parameters for
110        the error analysis. Default False.
111    gz : bool
112        If True, assumes that data is gzipped. If False, assumes JSON file.
113
114    Returns
115    -------
116    data : pandas.DataFrame
117        Dataframe with the content of the sqlite database.
118    """
119    if not fname.endswith('.csv') and not fname.endswith('.gz'):
120        fname += '.csv'
121
122    if gz is True:
123        if not fname.endswith('.gz'):
124            fname += '.gz'
125        with gzip.open(fname) as f:
126            re_import = pd.read_csv(f, keep_default_na=False)
127    else:
128        if fname.endswith('.gz'):
129            warnings.warn(f"Trying to read from {fname} without unzipping!", UserWarning, stacklevel=2)
130        re_import = pd.read_csv(fname, keep_default_na=False)
131
132    return _deserialize_df(re_import, auto_gamma=auto_gamma)
133
134
135def _serialize_df(df, gz=False):
136    """Serializes all Obs or Corr valued columns into json strings according to the pyerrors json specification.
137
138    Parameters
139    ----------
140    df : pandas.DataFrame
141        DataFrame to be serilized.
142    gz: bool
143        gzip the json string representation. Default False.
144    """
145    out = df.copy()
146    for column in out:
147        serialize = _need_to_serialize(out[column])
148
149        if serialize is True:
150            out[column] = out[column].transform(lambda x: create_json_string(x, indent=0) if not _is_null(x) else None)
151            if gz is True:
152                out[column] = out[column].transform(lambda x: gzip.compress(x.encode('utf-8')) if not _is_null(x) else gzip.compress(b''))
153    return out
154
155
156def _deserialize_df(df, auto_gamma=False):
157    """Deserializes all pyerrors json strings into Obs or Corr objects according to the pyerrors json specification.
158
159    Parameters
160    ----------
161    df : pandas.DataFrame
162        DataFrame to be deserilized.
163    auto_gamma : bool
164        If True applies the gamma_method to all imported Obs objects with the default parameters for
165        the error analysis. Default False.
166
167    Notes:
168    ------
169    In case any column of the DataFrame is gzipped it is gunzipped in the process.
170    """
171    # In pandas 3+, string columns use 'str' dtype instead of 'object'
172    string_like_dtypes = ["object", "str"] if int(pd.__version__.split(".")[0]) >= 3 else ["object"]
173    for column in df.select_dtypes(include=string_like_dtypes):
174        if len(df[column]) == 0:
175            continue
176        if isinstance(df[column].iloc[0], bytes):
177            if df[column].iloc[0].startswith(b"\x1f\x8b\x08\x00"):
178                df[column] = df[column].transform(lambda x: gzip.decompress(x).decode('utf-8') if not pd.isna(x) else '')
179
180        if df[column].notna().any():
181            df[column] = df[column].replace({r'^$': None}, regex=True)
182            i = 0
183            while i < len(df[column]) and pd.isna(df[column].iloc[i]):
184                i += 1
185            if i < len(df[column]) and isinstance(df[column].iloc[i], str):
186                if '"program":' in df[column].iloc[i][:20]:
187                    df[column] = df[column].transform(lambda x: import_json_string(x, verbose=False) if not pd.isna(x) else None)
188                    if auto_gamma is True:
189                        if isinstance(df[column].iloc[i], list):
190                            df[column].apply(lambda x: [o.gm() if o is not None else x for o in x] if x is not None else x)
191                        else:
192                            df[column].apply(lambda x: x.gm() if x is not None else x)
193        # Convert NA values back to Python None for compatibility with `x is None` checks
194        if df[column].isna().any():
195            df[column] = df[column].astype(object).where(df[column].notna(), None)
196    return df
197
198
199def _need_to_serialize(col):
200    serialize = False
201    i = 0
202    while i < len(col) and _is_null(col.iloc[i]):
203        i += 1
204    if i == len(col):
205        return serialize
206    if isinstance(col.iloc[i], (Obs, Corr)):
207        serialize = True
208    elif isinstance(col.iloc[i], list):
209        if all(isinstance(o, Obs) for o in col.iloc[i]):
210            serialize = True
211    return serialize
212
213
214def _is_null(val):
215    """Check if a value is null (None or NA), handling list/array values."""
216    return False if isinstance(val, (list, np.ndarray)) else pd.isna(val)
def to_sql(df, table_name, db, if_exists='fail', gz=True, **kwargs):
15def to_sql(df, table_name, db, if_exists='fail', gz=True, **kwargs):
16    """Write DataFrame including Obs or Corr valued columns to sqlite database.
17
18    Parameters
19    ----------
20    df : pandas.DataFrame
21        Dataframe to be written to the database.
22    table_name : str
23        Name of the table in the database.
24    db : str
25        Path to the sqlite database.
26    if exists : str
27        How to behave if table already exists. Options 'fail', 'replace', 'append'.
28    gz : bool
29        If True the json strings are gzipped.
30
31    Returns
32    -------
33    None
34    """
35    se_df = _serialize_df(df, gz=gz)
36    with closing(sqlite3.connect(db)) as con:
37        se_df.to_sql(table_name, con=con, if_exists=if_exists, index=False, **kwargs)

Write DataFrame including Obs or Corr valued columns to sqlite database.

Parameters
  • df (pandas.DataFrame): Dataframe to be written to the database.
  • table_name (str): Name of the table in the database.
  • db (str): Path to the sqlite database.
  • if exists (str): How to behave if table already exists. Options 'fail', 'replace', 'append'.
  • gz (bool): If True the json strings are gzipped.
Returns
  • None
def read_sql(sql, db, auto_gamma=False, **kwargs):
40def read_sql(sql, db, auto_gamma=False, **kwargs):
41    """Execute SQL query on sqlite database and obtain DataFrame including Obs or Corr valued columns.
42
43    Parameters
44    ----------
45    sql : str
46        SQL query to be executed.
47    db : str
48        Path to the sqlite database.
49    auto_gamma : bool
50        If True applies the gamma_method to all imported Obs objects with the default parameters for
51        the error analysis. Default False.
52
53    Returns
54    -------
55    data : pandas.DataFrame
56        Dataframe with the content of the sqlite database.
57    """
58    with closing(sqlite3.connect(db)) as con:
59        extract_df = pd.read_sql(sql, con=con, **kwargs)
60    return _deserialize_df(extract_df, auto_gamma=auto_gamma)

Execute SQL query on sqlite database and obtain DataFrame including Obs or Corr valued columns.

Parameters
  • sql (str): SQL query to be executed.
  • db (str): Path to the sqlite database.
  • auto_gamma (bool): If True applies the gamma_method to all imported Obs objects with the default parameters for the error analysis. Default False.
Returns
  • data (pandas.DataFrame): Dataframe with the content of the sqlite database.
def dump_df(df, fname, gz=True):
63def dump_df(df, fname, gz=True):
64    """Exports a pandas DataFrame containing Obs valued columns to a (gzipped) csv file.
65
66    Before making use of pandas to_csv functionality Obs objects are serialized via the standardized
67    json format of pyerrors.
68
69    Parameters
70    ----------
71    df : pandas.DataFrame
72        Dataframe to be dumped to a file.
73    fname : str
74        Filename of the output file.
75    gz : bool
76        If True, the output is a gzipped csv file. If False, the output is a csv file.
77
78    Returns
79    -------
80    None
81    """
82    for column in df:
83        serialize = _need_to_serialize(df[column])
84        if not serialize:
85            if all(isinstance(entry, (int, np.integer, float, np.floating)) for entry in df[column]):
86                if any([np.isnan(entry) for entry in df[column]]):
87                    warnings.warn("nan value in column " + column + " will be replaced by None", UserWarning, stacklevel=2)
88
89    out = _serialize_df(df, gz=False)
90
91    if not fname.endswith('.csv'):
92        fname += '.csv'
93
94    if gz is True:
95        if not fname.endswith('.gz'):
96            fname += '.gz'
97        out.to_csv(fname, index=False, compression='gzip')
98    else:
99        out.to_csv(fname, index=False)

Exports a pandas DataFrame containing Obs valued columns to a (gzipped) csv file.

Before making use of pandas to_csv functionality Obs objects are serialized via the standardized json format of pyerrors.

Parameters
  • df (pandas.DataFrame): Dataframe to be dumped to a file.
  • fname (str): Filename of the output file.
  • gz (bool): If True, the output is a gzipped csv file. If False, the output is a csv file.
Returns
  • None
def load_df(fname, auto_gamma=False, gz=True):
102def load_df(fname, auto_gamma=False, gz=True):
103    """Imports a pandas DataFrame from a csv.(gz) file in which Obs objects are serialized as json strings.
104
105    Parameters
106    ----------
107    fname : str
108        Filename of the input file.
109    auto_gamma : bool
110        If True applies the gamma_method to all imported Obs objects with the default parameters for
111        the error analysis. Default False.
112    gz : bool
113        If True, assumes that data is gzipped. If False, assumes JSON file.
114
115    Returns
116    -------
117    data : pandas.DataFrame
118        Dataframe with the content of the sqlite database.
119    """
120    if not fname.endswith('.csv') and not fname.endswith('.gz'):
121        fname += '.csv'
122
123    if gz is True:
124        if not fname.endswith('.gz'):
125            fname += '.gz'
126        with gzip.open(fname) as f:
127            re_import = pd.read_csv(f, keep_default_na=False)
128    else:
129        if fname.endswith('.gz'):
130            warnings.warn(f"Trying to read from {fname} without unzipping!", UserWarning, stacklevel=2)
131        re_import = pd.read_csv(fname, keep_default_na=False)
132
133    return _deserialize_df(re_import, auto_gamma=auto_gamma)

Imports a pandas DataFrame from a csv.(gz) file in which Obs objects are serialized as json strings.

Parameters
  • fname (str): Filename of the input file.
  • auto_gamma (bool): If True applies the gamma_method to all imported Obs objects with the default parameters for the error analysis. Default False.
  • gz (bool): If True, assumes that data is gzipped. If False, assumes JSON file.
Returns
  • data (pandas.DataFrame): Dataframe with the content of the sqlite database.