向熊猫DataFrame添加元信息/元数据


90

是否可以向熊猫DataFrame添加一些元信息/元数据?

例如,用于测量数据的仪器名称,负责的仪器等。

一种解决方法是用该信息创建一列,但是在每一行中存储一条信息似乎很浪费!


请注意@ryanjdillon答案(当前埋在底部附近),其中提到了更新的实验属性“ attrs”,这似乎是一个开始,也许
JohnE

Answers:


85

当然,像大多数Python对象一样,您可以将新属性附加到pandas.DataFrame

import pandas as pd
df = pd.DataFrame([])
df.instrument_name = 'Binky'

但是请注意,虽然可以附加属性的数据帧,操作上数据帧进行(如groupbypivotjoinloc仅举几例)可能会返回一个新的数据帧没有连接的元数据。熊猫还没有一种可靠的方法来传播 附加到DataFrames的元数据

可以将元数据保存在文件中。您可以在此处找到有关如何将元数据存储在HDF5文件中的示例。


5
+1为您选择乐器名称!您是否有尝试将这些额外的属性转储到HDFStore的经验?
Dan Allan

4
@DanAllan:如果使用store = pd.HDFStore(...),则可以使用存储属性store.root._v_attrs.key = value
unutbu

3
对于可能使用此功能的任何人:文档已在此添加了一个部分。pandas.pydata.org/pandas-docs/dev/cookbook.html#hdfstore
Dan Allan


4
在熊猫0.23.1中,通过分配字典,列表或元组创建新属性会发出警告(即df = pd.DataFrame(); df.meta = {}产生UserWarning: Pandas doesn't allow columns to be created via a new attribute name - see https://pandas.pydata.org/pandas-docs/stable/indexing.html#attribute-access)。(如果已经按照中的步骤创建了属性,则不会发出警告df = pd.DataFrame(); df.meta = ''; df.meta = {})。
teichert

13

自己碰到这个问题。从熊猫0.13开始,DataFrame在其上具有_metadata属性,该属性确实会通过返回新DataFrames的函数来保留。似乎也可以在序列化中幸存下来(我只尝试过json,但我想hdf也被覆盖了)。


16
_metadata不是公共API的一部分,因此强烈建议您不要依赖此功能。
shoyer

@Stephan您能详细说明一下吗?为什么成为公共API的一部分很重要?您的声明也适用于0.15版本吗?
TomCho 2015年

1
@TomCho是的,今天的答案仍然是正确的。您可以看一下xraygithub.com/xray/xray)作为支持元数据的带标签数组的另一个示例,尤其是如果您具有多维数据(.attrs属于
xray

17
_metadata实际上是一个类属性,而不是实例属性。因此DataFrame,只要模块保持加载状态,新实例就会从以前的实例继承。请勿_metadata用于任何用途。+1 xarray
j08lue

1
_metadata-一项不受支持的功能挽救了我的生命!谢谢。
joctee

12

并不是的。尽管您可以像@unutbu提到的那样将包含元数据的属性添加到DataFrame类中,但是许多DataFrame方法返回一个新的DataFrame,因此您的元数据将丢失。如果您需要操纵数据框,那么最好的选择是将元数据和数据框包装在另一个类中。在GitHub上查看此讨论:https : //github.com/pydata/pandas/issues/2485

当前有一个打开的拉取请求,用于添加MetaDataFrame对象,该对象将更好地支持元数据。


11

从熊猫1.0(可能更早)开始,现在有一个Dataframe.attrs属性。这是实验性的,但这可能是您将来想要的。例如:

import pandas as pd
df = pd.DataFrame([])
df.attrs['instrument_name'] = 'Binky'

此处的文档中找到它。

to_parquet然后再尝试使用from_parquet,它似乎并不持久,因此请确保使用用例进行验证。


这很有趣,并且似乎对于copy / loc / iloc仍然有效,但对于groupby却没有。
JohnE

只是一个建议,但也许可以举一个使用它的例子?该文档基本上什么都没有,但是仅仅通过玩弄它,我可以看到它被初始化为一个空字典,并且似乎已经被设置为必须是字典,尽管当然可以在其中嵌套一个列表,例如。
JohnE

1
您可能会发现此Stackoverflow讨论很有用,因为它演示了如何根据需要向镶木地板文件中添加自定义元数据
rdmolony,

1
@rdmolony太好了。我认为使用adataclass作为元数据,然后子类化DataFrame以像您共享的帖子中那样进行加载/转储的方法可能是一个不错的解决方案。
ryanjdillon

1
很好 与公认的答案相反,此方法在从pickle保存和加载后不会保留属性!
CGFoX

8

将任意属性附加到DataFrame对象的最佳答案是好的,但是如果使用字典,列表或元组,它将发出错误“ Pandas不允许通过新的属性名称创建列”。以下解决方案适用于存储任意属性。

from types import SimpleNamespace
df = pd.DataFrame()
df.meta = SimpleNamespace()
df.meta.foo = [1,2,3]

另外,如果您希望此方法在数据框的副本之间持久存在,则需要这样做pd.DataFrame._metadata += ["meta"]。请注意,这部分是Pandas的属性,而不是您特定数据

这种方法将不再起作用,因为df.meta会触发警告,Pandas不允许以这种方式生成新列。
anishtain4

@ anishtain4,我刚刚在Pandas 25.1(大约2周前发布)上进行了测试,该代码仍对我有效。由于df.meta是SimpleNamespace,因此不会触发该警告。熊猫不会尝试从中建立专栏。
bscan

6

正如其他答案和评论中所提到的那样,_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

4

谈到这一点很晚,我认为如果您需要元数据来通过I / O持久化,这可能会有所帮助。我一直使用一个相对较新的软件包h5io来完成此任务。

它应该使您能够从HDF5快速读取/写入几种常见格式,其中一种是数据帧。因此,例如,您可以将数据框放入字典中,并将元数据作为字段包含在字典中。例如:

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...

另一个选择是研究xray之类的项目,该项目在某些方面更复杂,但我认为它确实允许您使用元数据,并且很容易转换为DataFrame。


4

如@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

2

我一直在寻找解决方案,发现熊猫框架具有该属性 attrs

pd.DataFrame().attrs.update({'your_attribute' : 'value'})
frame.attrs['your_attribute']

只要您通过此属性,它就会始终粘贴在您的框架上!


请注意,attrs是实验性的,可能会更改而不会发出警告,但这是一个非常简单的解决方案。我想知道attrs是否会转移到新的数据帧。
Liquidgenius

不幸的是,attrs不会复制到新的数据帧中:(
Adam

1

我遇到了同样的问题,并使用了一种变通方法,该方法是使用元数据从字典中创建一个新的,较小的DF:

    meta = {"name": "Sample Dataframe", "Created": "19/07/2019"}
    dfMeta = pd.DataFrame.from_dict(meta, orient='index')

然后可以将此dfMeta与原始DF一起保存在pickle中。

请参阅在pickle文件中保存和加载多个对象?(Lutz的答案)对于使用pickle保存和检索多个数据帧的出色答案

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.