如何将PandasDataFrame的列解包为多个变量

goucqfw6  于 2023-01-19  发布在  其他
关注(0)|答案(2)|浏览(139)

如果维度匹配,列表或numpy数组可以解压缩为多个变量。对于3xN数组,以下操作将起作用:

import numpy as np 
a,b =          [[1,2,3],[4,5,6]]
a,b = np.array([[1,2,3],[4,5,6]])
# result: a=[1,2,3],   b=[4,5,6]

我怎样才能对PandasDataFrame的列实现类似的行为?扩展上面的例子:

import pandas as pd 
df = pd.DataFrame([[1,2,3],[4,5,6]])
df.columns = ['A','B','C']    # Rename cols and
df.index = ['i', 'ii']        # rows for clarity

以下内容未按预期工作:

a,b = df.T
# result: a='i',   b='ii'
a,b,c = df
# result: a='A',   b='B',   c='C'

不过,我想得到的是以下几点:

a,b,c = unpack(df)
result: a=df['A'], b=df['B'], c=df['C']

unpack这个函数在Pandas身上已经存在了吗?或者可以用一种简单的方法来模仿它?

mepcadol

mepcadol1#

我只是认为下面的工作,这已经接近我试图实现的:

a,b,c = df.T.values        # Common
a,b,c = df.T.to_numpy()    # Recommended
# a,b,c = df.T.as_matrix() # Deprecated

**详细信息:**和往常一样,事情比你想象的要复杂一些。请注意,一个pd.DataFramestores在Series中是分开列的。调用df.values(或更好的:df.to_numpy())可能是“昂贵的”,因为它将列组合在单个ndarray中,这可能涉及复制操作和类型转换。此外,结果容器具有能够容纳 Dataframe 中的所有数据的单个dtype

总之,上述方法会丢失每列的数据类型信息,而且可能会导致开销增加。从技术上讲,用以下方法之一迭代列会更干净(有更多的选择):

# The following alternatives create VIEWS!
a,b,c = (v for _,v in df.items())      # returns pd.Series
a,b,c = (df[c] for c in df)            # returns pd.Series

注意上面创建了视图!修改数据可能会触发SettingWithCopyWarning

a.iloc[0] = "blabla"    # raises SettingWithCopyWarning

如果要修改解压缩的变量,则必须复制列。

# The following alternatives create COPIES!
a,b,c = (v.copy() for _,v in df.items())      # returns pd.Series
a,b,c = (df[c].copy() for c in df)            # returns pd.Series
a,b,c = (df[c].to_numpy() for c in df)        # returns np.ndarray

虽然这更干净,但它需要更多的字符。我个人不推荐上述方法用于生产代码。但为了避免打字(eidogg.,在交互式环境会话中),它仍然是一个公平的选择。

# More verbose and explicit alternatives
a,b,c = df["the first col"], df["the second col"], df["the third col"]
a,b,c = df.iloc[:,0], df.iloc[:,1], df.iloc[:,2]
t40tm48m

t40tm48m2#

所示的dataframe.values方法确实是一个很好的解决方案,但它涉及到构建一个numpy数组。
如果你想在拆包后访问Pandas系列的方法,我个人使用不同的方法。
对于像我这样使用大量链式方法的人,我有一个解决方案,就是给panda添加一个自定义的解包方法。注意,这可能对生产管道不是很好,但在临时数据分析中非常方便。

df = pd.DataFrame({
    "lat": [30, 40], 
    "lon": [0, 1],
})

此方法涉及在.unpack()调用上返回生成器。

from typing import Tuple

def unpack(self: pd.DataFrame) -> Tuple[pd.Series]:
    return (
        self[col]
        for col in self.columns
    )

pd.DataFrame.unpack = unpack

这可以通过两种主要方式使用。
或者直接作为问题的解决方案:

lat, lon = df.unpack()

或者,也可以用在方法链接中。想象一个geo函数,它必须在第一个参数中获取纬度序列,在第二个参数中获取经度序列,命名为do_something_geographical(lat, lon)

df_result = (
    df
        .(...some method chaining...)
        .assign(
            geographic_result=lambda dataframe: do_something_geographical(dataframe[["lat", "lon"]].unpack())
        )
        .(...some method chaining...)
)

相关问题