132 lines
4.1 KiB
Python
132 lines
4.1 KiB
Python
"""inst.to_data_frame() helper functions."""
|
|
|
|
# Authors: The MNE-Python contributors.
|
|
# License: BSD-3-Clause
|
|
# Copyright the MNE-Python contributors.
|
|
|
|
from inspect import signature
|
|
|
|
import numpy as np
|
|
|
|
from ..defaults import _handle_default
|
|
from ._logging import logger, verbose
|
|
from .check import check_version
|
|
|
|
|
|
@verbose
|
|
def _set_pandas_dtype(df, columns, dtype, verbose=None):
|
|
"""Try to set the right columns to dtype."""
|
|
for column in columns:
|
|
df[column] = df[column].astype(dtype)
|
|
logger.info(f'Converting "{column}" to "{dtype}"...')
|
|
|
|
|
|
def _scale_dataframe_data(inst, data, picks, scalings):
|
|
ch_types = inst.get_channel_types()
|
|
ch_types_used = list()
|
|
scalings = _handle_default("scalings", scalings)
|
|
for tt in scalings.keys():
|
|
if tt in ch_types:
|
|
ch_types_used.append(tt)
|
|
for tt in ch_types_used:
|
|
scaling = scalings[tt]
|
|
idx = [ii for ii in range(len(picks)) if ch_types[ii] == tt]
|
|
if len(idx):
|
|
data[:, idx] *= scaling
|
|
return data
|
|
|
|
|
|
def _convert_times(times, time_format, meas_date=None, first_time=0):
|
|
"""Convert vector of time in seconds to ms, datetime, or timedelta."""
|
|
# private function; pandas already checked in calling function
|
|
from pandas import to_timedelta
|
|
|
|
if time_format == "ms":
|
|
times = np.round(times * 1e3).astype(np.int64)
|
|
elif time_format == "timedelta":
|
|
times = to_timedelta(times, unit="s")
|
|
elif time_format == "datetime":
|
|
times = to_timedelta(times + first_time, unit="s") + meas_date
|
|
return times
|
|
|
|
|
|
def _inplace(df, method, **kwargs):
|
|
# Handle transition: inplace=True (pandas <1.5) → copy=False (>=1.5)
|
|
# and 3.0 warning:
|
|
# E DeprecationWarning: The copy keyword is deprecated and will be removed in a
|
|
# future version. Copy-on-Write is active in pandas since 3.0 which utilizes a
|
|
# lazy copy mechanism that defers copies until necessary. Use .copy() to make
|
|
# an eager copy if necessary.
|
|
_meth = getattr(df, method) # used for set_index() and rename()
|
|
|
|
if check_version("pandas", "3.0"):
|
|
return _meth(**kwargs)
|
|
elif "copy" in signature(_meth).parameters:
|
|
return _meth(**kwargs, copy=False)
|
|
else:
|
|
_meth(**kwargs, inplace=True)
|
|
return df
|
|
|
|
|
|
@verbose
|
|
def _build_data_frame(
|
|
inst,
|
|
data,
|
|
picks,
|
|
long_format,
|
|
mindex,
|
|
index,
|
|
default_index,
|
|
col_names=None,
|
|
col_kind="channel",
|
|
verbose=None,
|
|
):
|
|
"""Build DataFrame from MNE-object-derived data array."""
|
|
# private function; pandas already checked in calling function
|
|
from pandas import DataFrame
|
|
|
|
from ..source_estimate import _BaseSourceEstimate
|
|
|
|
# build DataFrame
|
|
if col_names is None:
|
|
col_names = [inst.ch_names[p] for p in picks]
|
|
df = DataFrame(data, columns=col_names)
|
|
for i, (k, v) in enumerate(mindex):
|
|
df.insert(i, k, v)
|
|
# build Index
|
|
if long_format:
|
|
df = _inplace(df, "set_index", keys=default_index)
|
|
df.columns.name = col_kind
|
|
elif index is not None:
|
|
df = _inplace(df, "set_index", keys=index)
|
|
if set(index) == set(default_index):
|
|
df.columns.name = col_kind
|
|
# long format
|
|
if long_format:
|
|
df = df.stack().reset_index()
|
|
df = _inplace(df, "rename", columns={0: "value"})
|
|
# add column for channel types (as appropriate)
|
|
ch_map = (
|
|
None
|
|
if isinstance(inst, _BaseSourceEstimate)
|
|
else dict(
|
|
zip(
|
|
np.array(inst.ch_names)[picks],
|
|
np.array(inst.get_channel_types())[picks],
|
|
)
|
|
)
|
|
)
|
|
if ch_map is not None:
|
|
col_index = len(df.columns) - 1
|
|
ch_type = df["channel"].map(ch_map)
|
|
df.insert(col_index, "ch_type", ch_type)
|
|
# restore index
|
|
if index is not None:
|
|
df = _inplace(df, "set_index", keys=index)
|
|
# convert channel/vertex/ch_type columns to factors
|
|
to_factor = [
|
|
c for c in df.columns.tolist() if c not in ("freq", "time", "value")
|
|
]
|
|
_set_pandas_dtype(df, to_factor, "category")
|
|
return df
|