いくつかのメタ情報/メタデータをパンダのDataFrameに追加することは可能ですか?
たとえば、データの測定に使用される機器の名前、責任のある機器など。
回避策の1つは、その情報を含む列を作成することですが、すべての行に1つの情報を格納するのは無駄に思えます。
pandas.DataFrame
もちろん、ほとんどのPythonオブジェクトと同様に、新しい属性を:に付加できます。
import pandas as pd
df = pd.DataFrame([])
df.instrument_name = 'Binky'
ただし、属性をDataFrameにアタッチすることはできますが、DataFrameで実行される操作(、、、groupby
またはほんの数例)はpivot
、メタデータがアタッチされていない新しいDataFrameを返す場合があることに注意してください。Pandasには、DataFramesにアタッチされたメタデータを伝播する堅牢な方法がまだありません。join
loc
メタデータをファイルに保存することが可能です。メタデータをHDF5ファイルに保存する方法の例はここにあります。
pandas 1.0の時点で、おそらく以前は、Dataframe.attrs
プロパティがあります。これは実験的なものですが、これはおそらく将来あなたが望むものです。例えば:
import pandas as pd
df = pd.DataFrame([])
df.attrs['instrument_name'] = 'Binky'
こちらのドキュメントで見つけてください。
これを試してみてから、to_parquet
それfrom_parquet
が持続しないように見えるので、ユースケースでそれを確認してください。
自分でこの問題に遭遇しただけです。pandas 0.13以降、DataFrameには_metadata属性があり、新しいDataFrameを返す関数を介して永続化します。また、シリアル化にも問題なく耐えられるようです(jsonを試しただけですが、hdfもカバーされていると思います)。
あまり。@unutbuが言及しているように、メタデータを含む属性をDataFrameクラスに追加することはできますが、多くのDataFrameメソッドは新しいDataFrameを返すため、メタデータは失われます。データフレームを操作する必要がある場合は、メタデータとDataFrameを別のクラスでラップするのが最善のオプションです。GitHubでこのディスカッションを参照してください:https ://github.com/pydata/pandas/issues/2485
現在、メタデータをより適切にサポートするMetaDataFrameオブジェクトを追加するためのオープンプルリクエストがあります。
DataFrameオブジェクトに任意の属性を付加するという一番の答えは良いですが、辞書、リスト、またはタプルを使用すると、「パンダは新しい属性名で列を作成することを許可していません」というエラーが表示されます。次のソリューションは、任意の属性を格納するために機能します。
from types import SimpleNamespace
df = pd.DataFrame()
df.meta = SimpleNamespace()
df.meta.foo = [1,2,3]
他の回答やコメントで述べられているように、_metadata
はパブリックAPIの一部ではないため、本番環境で使用することは絶対に良い考えではありません。ただし、それでも研究用プロトタイピングで使用し、機能しなくなった場合は交換することをお勧めします。そして今はgroupby
/で動作しapply
ます。これは便利です。これは例です(他の回答では見つかりませんでした):
df = pd.DataFrame([1, 2, 2, 3, 3], columns=['val'])
df.my_attribute = "my_value"
df._metadata.append('my_attribute')
df.groupby('val').apply(lambda group: group.my_attribute)
出力:
val
1 my_value
2 my_value
3 my_value
dtype: object
@choldgrafが述べたように、xarrayは、データを比較し、複数のデータフレーム間で結果をプロットするときにメタデータを添付するための優れたツールであることがわかりました。
私の仕事では、いくつかのファームウェアリビジョンとさまざまなテストシナリオの結果を比較することがよくあります。この情報の追加は次のように簡単です。
df = pd.read_csv(meaningless_test)
metadata = {'fw': foo, 'test_name': bar, 'scenario': sc_01}
ds = xr.Dataset.from_dataframe(df)
ds.attrs = metadata
これにかなり遅れて来て、I/Oを介して永続化するメタデータが必要な場合にこれが役立つかもしれないと思いました。これを実現するために使用しているh5ioという比較的新しいパッケージがあります。
これにより、HDF5からいくつかの一般的な形式(そのうちの1つはデータフレーム)に対してすばやく読み取り/書き込みを実行できるようになります。したがって、たとえば、データフレームをディクショナリに配置し、メタデータをディクショナリのフィールドとして含めることができます。例えば:
save_dict = dict(data=my_df, name='chris', record_date='1/1/2016')
h5io.write_hdf5('path/to/file.hdf5', save_dict)
in_data = h5io.read_hdf5('path/to/file.hdf5')
df = in_data['data']
name = in_data['name']
etc...
もう1つのオプションは、 X線のようなプロジェクトを調べることです。これは、いくつかの点でより複雑ですが、メタデータを使用でき、DataFrameへの変換が非常に簡単だと思います。
私は解決策を探していましたが、パンダフレームにはプロパティがあることがわかりましたattrs
pd.DataFrame().attrs.update({'your_attribute' : 'value'})
frame.attrs['your_attribute']
この属性は、パスするたびに常にフレームに固定されます。
私は同じ問題を抱えていて、メタデータを使用して辞書から新しい、より小さなDFを作成する回避策を使用しました。
meta = {"name": "Sample Dataframe", "Created": "19/07/2019"}
dfMeta = pd.DataFrame.from_dict(meta, orient='index')
このdfMetaは、元のDFと一緒にピクルスなどに保存できます。
ピクルスファイルへの複数のオブジェクトの保存とロードを参照してください。(Lutzの回答)pickleを使用して複数のデータフレームを保存および取得する際の優れた回答
パンダ(例df.my_metadata = "source.csv"
)で生の属性を追加することはお勧めできません。
最新バージョン(Python 3.8では1.2.4)でも、これを行うと、などの非常に単純な操作を行うときにランダムにsegfaultが発生しread_csv
ます。正常に動作するため、デバッグは困難ですread_csv
が、後で(一見ランダムに)データフレームがメモリから解放されていることがわかります。
パンダに関連するcpython拡張機能は、データフレームのデータレイアウトについて非常に明確な仮定をしているようです。
attrs
現在、メタデータプロパティを使用する唯一の安全な方法です:
https ://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.attrs.html
例えば
df.attrs.update({'my_metadata' : "source.csv"})
すべてのシナリオでattrsがどのように動作するかは、完全には具体化されていません。この問題で予想される動作に関するフィードバックを提供するのに役立ちますattrs
:https ://github.com/pandas-dev/pandas/issues/28283
(Pandasの公式ドキュメントの)元のプロパティの定義のセクションを参照し、fromのサブクラス化がオプションである場合は、次の点に注意してください。pandas.DataFrame
元のデータ構造に追加のプロパティを持たせるには、
pandas
追加されたプロパティを通知する必要があります。
したがって、あなたができること-名前MetaedDataFrame
が任意に選択されている場合-は
class MetaedDataFrame(pd.DataFrame):
"""s/e."""
_metadata = ['instrument_name']
@property
def _constructor(self):
return self.__class__
# Define the following if providing attribute(s) at instantiation
# is a requirement, otherwise, if YAGNI, don't.
def __init__(
self, *args, instrument_name: str = None, **kwargs
):
super().__init__(*args, **kwargs)
self.instrument_name = instrument_name
_metadata
次に、(事前に指定された)属性を使用してデータフレームをインスタンス化します。
>>> mdf = MetaedDataFrame(instrument_name='Binky')
>>> mdf.instrument_name
'Binky'
またはインスタンス化後でも
>>> mdf = MetaedDataFrame()
>>> mdf.instrument_name = 'Binky'
'Binky'
警告なし(2021/06/15現在):シリアル化と~.copy
魅力のように機能します。また、このようなアプローチでは、たとえば、プロパティ(またはメソッド)などのいくつかのinstrument_name
ベースのメンバーをに追加することで、APIを充実させることができます。MetaedDataFrame
[...]
@property
def lower_instrument_name(self) -> str:
if self.instrument_name is not None:
return self.instrument_name.lower()
[...]
>>> mdf.lower_instrument_name
'binky'
...しかし、これはこの質問の範囲をかなり超えています...
pandas.pydata.orgによると、データフレームをHDFStoreに保存しようとしている場合、推奨されるアプローチは次のとおりです。
import pandas as pd
df = pd.DataFrame(dict(keys=['a', 'b', 'c'], values=['1', '2', '3']))
df.to_hdf('/tmp/temp_df.h5', key='temp_df')
store = pd.HDFStore('/tmp/temp_df.h5')
store.get_storer('temp_df').attrs.attr_key = 'attr_value'
store.close()