pandas 重新排序分组数据框中的列子集

Posted

技术标签:

【中文标题】pandas 重新排序分组数据框中的列子集【英文标题】:pandas reorder subset of columns from a grouped data frame 【发布时间】:2017-02-13 06:43:12 【问题描述】:

我有按月分组的预测数据。 原始数据框 something 像这样:

>>clean_table_grouped[0:5]
       STYLE    COLOR    SIZE   FOR
MONTH                           01/17    10/16   11/16    12/16
    0 #######   ######   ####   0.0      15.0    15.0     15.0
    1 #######   ######   ####   0.0      15.0    15.0     15.0
    2 #######   ######   ####   0.0      15.0    15.0     15.0
    3 #######   ######   ####   0.0      15.0    15.0     15.0
    4 #######   ######   ####   0.0      15.0    15.0     15.0

>>clean_table_grouped.ix[0:,"FOR"][0:5] 
 MONTH  01/17  10/16  11/16  12/16
0        0.0   15.0   15.0   15.0
1        0.0   15.0   15.0   15.0
2        0.0   15.0   15.0   15.0
3        0.0   15.0   15.0   15.0
4        0.0   15.0   15.0   15.0

我只想按以下方式重新排列这 4 列:

(保持数据框的其余部分不变)

MONTH    10/16  11/16  12/16  01/17
0        15.0   15.0   15.0   0.0
1        15.0   15.0   15.0   0.0
2        15.0   15.0   15.0   0.0
3        15.0   15.0   15.0   0.0
4        15.0   15.0   15.0   0.0

我尝试的解决方案是在以下帖子之后重新排序子集的列: How to change the order of DataFrame columns?

我先抓取列列表并对其进行排序

 >>for_cols = clean_table_grouped.ix[:,"FOR"].columns.tolist()
 >>for_cols.sort(key = lambda x: x[0:2])   #sort by month ascending
 >>for_cols.sort(key = lambda x: x[-2:])   #then sort by year ascending

查询数据框工作正常

>>clean_table_grouped.ix[0:,"FOR"][for_cols]
MONTH   10/16   11/16  12/16  01/17
0        15.0    15.0    15.0    0.0
1        15.0    15.0    15.0    0.0
2        15.0    15.0    15.0    0.0
3        15.0    15.0    15.0    0.0
4        15.0    15.0    15.0    0.0

但是,当我尝试在原始表中设置值时,我得到一个“NaN”表:

>>clean_table_grouped.ix[0:,"FOR"] = clean_table_grouped.ix[0:,"FOR"][for_cols]
>>clean_table_grouped.ix[0:,"FOR"]
MONTH  01/17  10/16  11/16  12/16
0        NaN    NaN    NaN    NaN
1        NaN    NaN    NaN    NaN
2        NaN    NaN    NaN    NaN
3        NaN    NaN    NaN    NaN
4        NaN    NaN    NaN    NaN
5        NaN    NaN    NaN    NaN

我也尝试过压缩以避免链式语法 (.ix[][])。 这避免了 NaN,但是,它不会更改数据框 -__-

>>for_cols = zip(["FOR", "FOR", "FOR", "FOR"], for_cols)
>>clean_table_grouped.ix[0:,"FOR"] = clean_table_grouped.ix[0:,for_cols]
>>clean_table_grouped.ix[0:,"FOR"]
 MONTH  01/17  10/16  11/16  12/16
 0        0.0   15.0   15.0   15.0
 1        0.0   15.0   15.0   15.0
 2        0.0   15.0   15.0   15.0
 3        0.0   15.0   15.0   15.0
 4        0.0   15.0   15.0   15.0

我意识到我正在使用 ix 重新分配值。但是,我过去曾在未分组的数据帧上使用过这种技术,并且效果很好。

如果此问题已在另一篇文章中得到解答(以明确的方式),请提供链接。我搜索了但找不到类似的东西。

编辑: 我找到了解决方案。通过按照您希望列排序的顺序创建新的多索引数据框来手动重新索引。我在下面发布了解决方案。

【问题讨论】:

你原来的DataFrame的结构是什么? 【参考方案1】:

我自己的解决方案是基于以下帖子的第二个答案: How can I reorder multi-indexed dataframe columns at a specific level

差不多...只需使用您想要的多索引创建一个新的数据框。 多索引数据帧不太支持尝试使用 .ix、.loc、.iloc 插入值。如果您希望完全更改列子集的值(而不仅仅是交换),Nickil 的分离和重新连接表的解决方案绝对是要走的路。但是,如果您只想交换列,则以下内容可以正常工作。我选择了这个作为 Nickil 解决方案的答案,因为这个解决方案对我来说效果更好,因为除了按月分组的“FOR”之外,我还有其他数据,并且它让我在重新排序列时更加灵活

首先,按照您想要的顺序存储列表:

>>reindex_list = ['STYLE','COLOR','SIZE','FOR'] #desired order
>>month_list = clean_table_grouped.ix[0:,"FOR"].columns.tolist()
>>month_list.sort(key = lambda x: x[0:2]) #sort by month ascending
>>month_list.sort(key = lambda x: x[-2:]) #sort by year ascending

然后创建一个压缩列表,其中样式、颜色、尺寸用“”压缩,“FOR”每个月用压缩。像这样:

[('STYLE',''),('COLOR',''),..., ('FOR','10/16'), ('FOR','11/16'), ...]

这是一个自动执行的算法:

>>zip_list = []
>>
for i in reindex_list:
if i in ['FOR']:
    for j in month_list:
        if j != '':
            zip_list.append(zip([i],[j])[0])
else:
    zip_list.append(zip([i],[''])[0])

然后从你刚刚压缩的元组列表中创建一个多索引:

>>multi_cols = pd.MultiIndex.from_tuples(zip_list, names=['','MONTH'])

最后,使用新的多索引从旧数据框创建一个新数据框:

>>clean_table_grouped_ordered = pd.DataFrame(clean_table_grouped, columns=multi_cols)
>>clean_table_grouped_ordered[0:5]
       STYLE COLOR SIZE FOR
 MONTH                  10/16   11/16   12/16  01/17
       ####  ####  ###  15.0    15.0    15.0    0.0
       ####  ####  ###  15.0    15.0    15.0    0.0
       ####  ####  ###  15.0    15.0    15.0    0.0
       ####  ####  ###  15.0    15.0    15.0    0.0
       ####  ####  ###  15.0    15.0    15.0    0.0
       ####  ####  ###  15.0    15.0    15.0    0.0

【讨论】:

【参考方案2】:

对包含日期字符串的列名进行排序,然后将其用作子集以按特定顺序返回列:

from datetime import datetime
df[sorted(df.columns, key=lambda x: datetime.strptime(x, '%m/%y'))]


玩具数据:

from datetime import datetime
np.random.seed(42)

cols = [['STYLE', 'COLOR', 'SIZE', 'FOR', 'FOR', 'FOR', 'FOR'],
        ['', '', '', '01/17', '10/16', '11/16', '12/16']]
tups = list(zip(*cols))
index = pd.MultiIndex.from_tuples(tups, names=[None, 'MONTH'])
clean_table_grouped = pd.DataFrame(np.random.randint(0, 100, (100, 7)), 
                                   index=np.arange(100), columns=index)
clean_table_grouped = clean_table_grouped.head()
clean_table_grouped

将多索引DF 拆分为两部分,其中一个包含预测值,另一个包含DF

for_df = clean_table_grouped[['FOR']]
clean_table_grouped = clean_table_grouped.drop(['FOR'], axis=1, level=0)

预测DF:

for_df

剩余DF:

clean_table_grouped

通过应用与预编辑帖子中相同的过程对预测 DF 中的列进行排序。

order = sorted(for_df['FOR'].columns.tolist(), key=lambda x: datetime.strptime(x, '%m/%y'))

通过对已排序的列的list 进行子集化,使DF 的顺序相同。

for_df = for_df['FOR'][order]

将预测DF 与自身连接以创建类似多索引的列。

for_df = pd.concat([for_df, for_df], axis=1, keys=['FOR'])

最后,将它们加入公共索引。

clean_table_grouped.join(for_df)

【讨论】:

这可以交换数据框的 子集 中的列顺序,它是一种比我自己的交换列顺序更优雅的解决方案。但是,我的问题是将交换顺序替换为原始数据框而不影响其他列(样式、颜色、大小)。由于我没有提供我希望更新的数据框的原始结构,因此我没有否决这个答案。谢谢! 知道了。现在我知道在您提供起始DF 后您在问什么,我重新创建了一个类似的DF 来为您提供所需的输出。 查看编辑 尼克尔,解决了我的朋友,解决了。打的好。我不得不说,我没想到会有这么复杂的解决方案。但是,您的解决方案完美运行:)。我想指出,除了“FOR”之外,我还有其他分组数据;连接将 for_df 表附加到原始表的最后,但这并不是真正的问题。它确实适当地交换了“FOR”列,并以无缝方式将其连接回原始表。 很高兴我能够完全解决它。但我必须承认,我花了一段时间才弄清楚并最终找到解决方案,并因此真正享受了整个过程。感谢您的提问,祝您一切顺利!

以上是关于pandas 重新排序分组数据框中的列子集的主要内容,如果未能解决你的问题,请参考以下文章

Pandas 根据列中的最小值到最大值对行进行重新排序

熊猫数据框:按列子集+按另一列分组

对 pandas 数据框中的连续值进行分组

Python - Pandas,重新采样数据集以具有平衡的类

根据列名重新排序熊猫数据框中的列[重复]

根据列名重新排序熊猫数据框中的列[重复]