【问题标题】:pandas column values to row values熊猫列值到行值
【发布时间】:2017-07-21 20:02:22
【问题描述】:

我有一个数据集(171 列),当我将它放入我的数据框时,它看起来像这样-

ANO MNO UJ2010  DJ2010   UF2010 DF2010   UM2010 DM2010    UA2010    DA2010 ...
1   A   113   06/01/2010    129 06/02/2010  143 06/03/2010  209 05/04/2010 ...
2   B   218   06/01/2010    211 06/02/2010  244 06/03/2010  348 05/04/2010 ...
3   C   22    06/01/2010    114 06/02/2010  100 06/03/2010  151 05/04/2010 ...

现在我想像这样更改我的数据框 -

    ANO MNO Time        Unit
    1   A   06/01/2010  113
    1   A   06/02/2010  129
    1   A   06/03/2010  143
    2   B   06/01/2010  218
    2   B   06/02/2010  211
    2   B   06/03/2010  244
    3   C   06/01/2010  22
    3   C   06/02/2010  114
    3   C   06/03/2010  100
....
.....

我尝试使用pd.melt,但我认为它不能满足我的目的。我该怎么做?

【问题讨论】:

    标签: python pandas numpy jupyter-notebook jupyter


    【解决方案1】:

    在过滤要在不同标题下分组的列后,使用pd.lreshape 作为pd.melt 的接近替代品。

    通过使用pd.lreshape,当您将字典对象作为groups 参数注入时,键将采用新的标题名称,并且作为值馈送到此dict 的所有列名称列表将是投在那个单一的标题下。因此,它会在转换后生成一个长格式的DF

    最后对DF w.r.t 未使用的列进行排序,以相应地对齐它们。

    然后,在末尾添加一个reset_index(drop=True),通过删除中间索引将索引轴重新标记为默认整数值。

    d = pd.lreshape(df, {"Time": df.filter(regex=r'^D').columns, 
                         "Unit": df.filter(regex=r'^U').columns})
    
    d.sort_values(['ANO', 'MNO']).reset_index(drop=True)
    


    如果分组列的长度不匹配,则:

    from itertools import groupby, chain
    
    unused_cols = ['ANO', 'MNO']
    cols = df.columns.difference(unused_cols)
    
    # filter based on the common strings starting from the first slice upto end.
    fnc = lambda x: x[1:] 
    pref1, pref2 = "D", "U"
    
    # Obtain groups based on a common interval of slices.
    groups = [list(g) for n, g in groupby(sorted(cols, key=fnc), key=fnc)]
    
    # Fill single length list with it's other char counterpart.
    fill_missing = [i if len(i)==2 else i + 
                    [pref1 + i[0][1:] if i[0][0] == pref2 else pref2 + i[0][1:]]
                    for i in groups]
    
    # Reindex based on newly obtained column names.
    df = df.reindex(columns=unused_cols + list(chain(*fill_missing)))
    

    如上所述,使用pd.lreshape 继续相同的步骤,但这次包含dropna=False 参数。

    【讨论】:

    • pd.lreshape 很棒 +1 :-)
    • 我可能错了,但在pd.lreshape 上找不到任何文档,您能否再解释一下代码?你能给我文档参考吗?
    • 我已经更新了我的帖子。 如果您使用的是 Jupyter,pd.lreshape?? 应该会在弹出窗口中向您显示底层代码。 AFAIK,目前仍处于实验阶段,因此文档页面中没有它。
    • 它们是否都以相同的UD 前缀开头?如果没有,您打算如何对它们进行分组?
    • 当我尝试在我的数据集中运行你的 sn-p 时,它显示 ValueError: All column lists must be same length。我需要填写所有Nan。因为有一些列对于一个帐户来说根本没有任何价值
    【解决方案2】:

    您可以通过stack 进行整形,但首先在具有%// 的列中创建MultiIndex

    MultiIndex 值将 TimeUnit 映射到 MultiIndex 的第二级,通过地板除​​法 (//) 2,每对的差异由模除法 (%) 创建.

    然后stack使用//创建的最后一层,并在index中创建新的MultiIndex层,这不是必需的,所以被reset_index(level=2, drop=True)删除。

    用于将第一级和第二级转换为columns 的最后一个reset_index。

    [[1,0]] 用于交换列以进行更改排序。

    df = df.set_index(['ANO','MNO'])
    cols = np.arange(len(df.columns))
    df.columns = [cols % 2, cols // 2]
    
    print (df)
               0           1    0           1    0           1    0           1
               0           0    1           1    2           2    3           3
    ANO MNO                                                                    
    1   A    113  06/01/2010  129  06/02/2010  143  06/03/2010  209  05/04/2010
    2   B    218  06/01/2010  211  06/02/2010  244  06/03/2010  348  05/04/2010
    3   C     22  06/01/2010  114  06/02/2010  100  06/03/2010  151  05/04/2010
    
    df = df.stack()[[1,0]].reset_index(level=2, drop=True).reset_index()
    df.columns = ['ANO','MNO','Time','Unit']
    print (df)
        ANO MNO        Time  Unit
    0     1   A  06/01/2010   113
    1     1   A  06/02/2010   129
    2     1   A  06/03/2010   143
    3     1   A  05/04/2010   209
    4     2   B  06/01/2010   218
    5     2   B  06/02/2010   211
    6     2   B  06/03/2010   244
    7     2   B  05/04/2010   348
    8     3   C  06/01/2010    22
    9     3   C  06/02/2010   114
    10    3   C  06/03/2010   100
    11    3   C  05/04/2010   151
    

    编辑:

    #last column is missing 
    print (df)
       ANO MNO  UJ2010      DJ2010  UF2010      DF2010  UM2010      DM2010  UA2010
    0    1   A     113  06/01/2010     129  06/02/2010     143  06/03/2010     209
    1    2   B     218  06/01/2010     211  06/02/2010     244  06/03/2010     348
    2    3   C      22  06/01/2010     114  06/02/2010     100  06/03/2010     151
    

    df = df.set_index(['ANO','MNO'])
    #MultiIndex is created by first character of column names with all another
    df.columns = [df.columns.str[0], df.columns.str[1:]]
    print (df)
                U           D     U           D     U           D     U
            J2010       J2010 F2010       F2010 M2010       M2010 A2010
    ANO MNO                                                            
    1   A     113  06/01/2010   129  06/02/2010   143  06/03/2010   209
    2   B     218  06/01/2010   211  06/02/2010   244  06/03/2010   348
    3   C      22  06/01/2010   114  06/02/2010   100  06/03/2010   151
    
    
    #stack add missing values, replace them by NaN
    df = df.stack().reset_index(level=2, drop=True).reset_index()
    df.columns = ['ANO','MNO','Time','Unit']
    print (df)
        ANO MNO        Time  Unit
    0     1   A         NaN   209
    1     1   A  06/02/2010   129
    2     1   A  06/01/2010   113
    3     1   A  06/03/2010   143
    4     2   B         NaN   348
    5     2   B  06/02/2010   211
    6     2   B  06/01/2010   218
    7     2   B  06/03/2010   244
    8     3   C         NaN   151
    9     3   C  06/02/2010   114
    10    3   C  06/01/2010    22
    11    3   C  06/03/2010   100
    

    【讨论】:

    • 当然,等一下
    • 根据列行开关,您的代码可以工作,但现在的问题是,我在特定列中缺少值。实际上,这是一种将它们的值左移到其他列的方式。我能让你理解这个场景吗?
    • 解决方法很简单——添加参数dropna=False - df.stack(dropna=False)
    • 或问题是列中的某些所有值都丢失了?例如。如果您的样本UJ2010, DJ2010 丢失了DJ2010
    • 是的,这正是问题所在,有些列缺少值。现在我该怎么办?
    【解决方案3】:

    您可以为此使用ilocpd.concat。解决方案很简单 - 只需将所有相关列(通过 iloc 选择)一个接一个地垂直堆叠并将它们连接起来:

    def rename(sub_df):
        sub_df.columns = ["ANO", "MNO", "Time", "Unit"]
        return sub_df
    
    pd.concat([rename(df.iloc[:, [0, 1, x+1, x]])
               for x in range(2, df.shape[1], 2)])
    
        ANO     MNO     Time    Unit
    0   1       A   06/01/2010  113
    1   2       B   06/01/2010  218
    2   3       C   06/01/2010  22
    0   1       A   06/02/2010  129
    1   2       B   06/02/2010  211
    2   3       C   06/02/2010  114
    0   1       A   06/03/2010  143
    1   2       B   06/03/2010  244
    2   3       C   06/03/2010  100
    0   1       A   05/04/2010  209
    1   2       B   05/04/2010  348
    2   3       C   05/04/2010  151
    

    【讨论】:

    • 我说我有171列所以我需要更改concat方法中的参数吗?
    • @pdfarhad 不,你不知道,它已经通过df.shape[1] 包含在内。范围会根据您的输入数据框自动调整。
    猜你喜欢
    • 2017-05-23
    • 1970-01-01
    • 1970-01-01
    • 2014-06-16
    • 1970-01-01
    • 2017-04-17
    • 2021-05-19
    • 2022-07-21
    • 2021-02-23
    相关资源
    最近更新 更多