如何转换大数据框

How to transform a large data frame

我想转换以下数据框,但似乎无法获得执行此操作的正确函数。每当我使用 'melt' 时,系统都会提示我转换为数组,但数组似乎不接受列名。

无论如何,任何帮助解决这个问题的方法:

一个 B C1 C1.A C2 C2.A
PC 11001 核心 SE 新建

进入这个:

一个 B C C.A
PC 11001 核心
PC 11001 SE 新建

将不胜感激。

第一个和第二个 df 的代码。

df1 = {'A': ['PC'], 'B': [11001],'C1':['Core'],'C1.A':['Old'],'C2':['SE'],'C2.A':['New']}

df1 = pd.DataFrame(data=df1)`


df2 = {'A': ['PC','PC'], 'B': [11001,11001],'C':['Core','SE'],'C.A':['Old','New']}

df2 = pd.DataFrame(data=df2)

稍微重新格式化一下列,就可以使用 pd.wide_to_long

df.columns = df.columns.str.replace(r'C(\d+).A', r'C.A', regex=True)
df = (
    pd.wide_to_long(df, stubnames=['C', 'C.A'], i=['A', 'B'], j='drop')
        .droplevel(axis=0, level='drop')
        .reset_index()
)

df:

    A      B     C  C.A
0  PC  11001  Core  Old
1  PC  11001    SE  New

df 中的列更改为:

    A      B    C1 C1.A  C2 C2.A
0  PC  11001  Core  Old  SE  New

df.columns = df.columns.str.replace(r'C(\d+).A', r'C.A', regex=True)
    A      B    C1 C.A1  C2 C.A2
0  PC  11001  Core  Old  SE  New

然后 wide_to_long 存根名称 CC.A


不影响df的替代方案:

new_df = (
    pd.wide_to_long(
        df.rename(columns=dict(
            zip(df.columns,
                df.columns.str.replace(r'C(\d+).A', r'C.A', regex=True)))
        ),
        stubnames=['C', 'C.A'],
        i=['A', 'B'],
        j='drop')
        .droplevel(axis=0, level='drop')
        .reset_index()
)

new_df:

    A      B     C  C.A
0  PC  11001  Core  Old
1  PC  11001    SE  New

df:

    A      B    C1 C1.A  C2 C2.A
0  PC  11001  Core  Old  SE  New

使用 replace 将列转换为 MultiIndex,然后使用 split,然后 stack 重塑框架以将其转换为所需格式

df = df1.set_index(['A', 'B'])
df.columns = df.columns\
               .str.replace(r'^(\D+)(\d+)(.*)', r'_')\
               .str.split('_', expand=True)

df = df.stack().droplevel(2).reset_index()

    A      B     C  C.A
0  PC  11001  Core  Old
1  PC  11001    SE  New

感谢您输入代码。我会接受的。 :)
以下是一些想法:

  • 您已经对单行结果进行了硬编码,这是一个好的开始。
  • 我们可以将该代码与自定义函数一起使用,然后使用 groupy.apply 从单行数据生成新的两行结果(数据帧)。 groupby.apply 将处理与您的新数据框的组合。
  • 之后,如果需要重新索引。

首先,我们为 groupby 定制一个应用函数:

def make_new_df_from_row(df):
    row = df.iloc[0, :] # df is each df split by groupby
    dd = pd.DataFrame({ #configure your hardcode
        'A': row.A, 'B': row.B,
        'C':[row.C1, row.C2],
        'C.A':[row['C1.A'], row['C2.A']] #column name with '.' cannot use row.C1.A
    })
    return dd

然后,使用df2 = df1.groupby(lambda x:x, group_keys=False).apply(make_new_df_from_row)得到你想要的结果。

有来自colab的截图:

一些笔记:

  • groupby 接受一个使用索引作为输入并从函数输出中拆分数据帧的函数,这里只使用一个 lambda 函数,return 索引本身,按每一行(单行数据帧)拆分数据帧.
  • group_keys=False 表示不要 return 键(分组索引)
  • groupby.apply 接受一个输入是每个 groupby 数据帧的函数,你可以 return 一个 pd.Series 或 pd.Dataframe 取决于你的需要。在这里,我们 return 来自您的代码输入的两行数据框(有一些变量更改)

除了已经提供的其他解决方案之外,pivot_longer from pyjanitor 是另一种选择 -> 您的列具有我们可以利用的模式(一些以数字结尾,另一些以 A 结尾):

# pip install pyjanitor
import janitor
import pandas as pd
df.pivot_longer(index=['A', 'B'], 
                names_to = ['C', 'C.A'], 
                names_pattern = ['.+\d$', '.+A$'])
 
    A      B     C  C.A
0  PC  11001  Core  Old
1  PC  11001    SE  New

names_to中的列成为新的列名,并映射到与names_pattern中的正则表达式相匹配的旧列。