Pandas 从长到宽(未熔化或类似的?)

Pandas long to wide (unmelt or similar?)

我有一个像这样的融化的长格式数据框:

name = ["A", "A", "B", "B"]
varA = [1, 2, 1, 2]
varB = [200, 250, 200, 250]
val = [4, 8, 1, 0]

df = pd.DataFrame(
    data=zip(name, varA, varB, val), columns=["name", "varA", "varB", "val"]
)

怎么改成这样?

有一个类似的问题,所以我尝试了以下,抛出了错误ValueError: Index contains duplicate entries, cannot reshape

df2 = (df.set_index(['varA','varB'])
        .stack()
        .unstack(0)
        .reset_index()
        .rename_axis(None, axis=1))

我相信对于熟悉所有 Pandas functions/methods 的人来说这很容易,但是对于普通用户来说还有大量的功能需要跟踪!

  1. 制作一个辅助列,指定哪些行与 name-1/val-1 和 name-2/val-2
  2. 相关联
  3. 使用这个新列,我们现在可以旋转数据而不会遇到“重复条目”错误

清理输出:

  1. 对列进行排序以匹配您的输出
  2. 枢轴将 return 具有柱状多索引的数据框。我们需要通过组合级别
  3. 来展平它

pandas > 1.0.5

id_vars = ["varA", "varB"]

# Create an id column that tracks the id_vars
# Pivot using the id column
# Sort the columns to match OP expected output
pivoted_df = (
    df.assign(
        id=df.groupby(id_vars).cumcount().add(1).astype(str)
    )
    .pivot(index=id_vars, columns="id", values=["name", "val"])
    .sort_index(level=1, axis=1)
)

# flatten the column multiindex, insert the row index as values
flattened_columns = pivoted_df.columns.map("-".join)
pivoted_df = (
    pivoted_df.set_axis(flattened_columns, axis=1)
    .reset_index()
)

print(pivoted_df)
   varA  varB name-1 val-1 name-2 val-2
0     1   200      A     4      B     1
1     2   250      A     8      B     0

pandas <= 1.0.5

  • pivot 在这些版本中不支持使用列表作为参数。解决方法是将 pivot_table 与非聚合 aggfunc 一起使用以防止意外聚合。
id_vars = ["varA", "varB"]

# Create an id column that tracks the id_vars
# Pivot using the id column
# Sort the columns to match OP expected output
pivoted_df = (
    df.assign(
        id=df.groupby(id_vars).cumcount().add(1).astype(str)
    )
    .pivot_table(index=id_vars, columns="id", values=["name", "val"], aggfunc=lambda x: x)
    .sort_index(level=1, axis=1)
)

# flatten the column multiindex, insert the row index as values
flattened_columns = pivoted_df.columns.map("-".join)
pivoted_df = (
    pivoted_df.set_axis(flattened_columns, axis=1)
    .reset_index()
)