Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/317.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
排序后的多索引后的python groupby不正确_Python_Sorting_Pandas - Fatal编程技术网

排序后的多索引后的python groupby不正确

排序后的多索引后的python groupby不正确,python,sorting,pandas,Python,Sorting,Pandas,尊敬的python/pandas专家: 我在对多索引数据帧的索引进行排序时遇到问题。更具体地说,排序似乎有效,但之后的groupby操作再次“忘记”了排序。供参考:我正在运行python 3.4.3(由anaconda编写)和pandas 0.16.2(np19py34_0) 现在详细说明我要做的事情 我创建了一个multindex数据框,如下所示 import pandas as pd label="sdjks" sidechar="B" mi_level_fields = (label, s

尊敬的python/pandas专家:

我在对多索引数据帧的索引进行排序时遇到问题。更具体地说,排序似乎有效,但之后的groupby操作再次“忘记”了排序。供参考:我正在运行python 3.4.3(由anaconda编写)和pandas 0.16.2(np19py34_0)

现在详细说明我要做的事情

我创建了一个multindex数据框,如下所示

import pandas as pd
label="sdjks"
sidechar="B"
mi_level_fields = (label, sidechar)
mi_level_names = ["Label", "Side"]
pipeinfo_index = pd.MultiIndex.from_tuples([mi_level_fields], names=mi_level_names)

pipeinfoDF = pd.DataFrame(index=pipeinfo_index, columns=[])
pipeinfoDF.ix[(label, sidechar), "Nc"] = 10
pipeinfoDF.ix[(label, "C"), "Nc"] = 10
pipeinfoDF.ix[("ztest", "C"), "Nc"] = 400
pipeinfoDF.ix[("ztest", "B"), "Nc"] = 400
pipeinfoDF.ix[("yaki", "B"), "Nc"] = 1
pipeinfoDF.ix[("yaki", "C"), "Nc"] = 1
这个pipeinfoDF数据帧现在看起来像

             Nc
Label Side     
sdjks B      10
      C      10
ztest C     400
      B     400
yaki  B       1
      C       1
现在我想对数据帧的索引进行排序,以使NC列按升序排列。这可以通过

pipeinfoDF.sort_index(by=["Nc"], inplace=True, ascending=True)
这确实正确地产生了使用

print(pipeinfoDF.head())

             Nc
Label Side     
yaki  B       1
      C       1
sdjks B      10
      C      10
ztest C     400
      B     400
然而,当我想要循环这个多索引数据帧的行时,问题就出现了,我通常使用它

for (label, df) in pipeinfoDF.groupby(level=0, sort=False):
    side_list = df.index.get_level_values('Side')
    for side in side_list:
        data = pipeinfoDF.ix[(label, side)]
        print(label, side, data.Nc)
现在作为一个输出

sdjks B 10.0
sdjks C 10.0
ztest C 400.0
ztest B 400.0
yaki B 1.0
yaki C 1.0
正如您所看到的,尽管head()语句显示数据帧已正确排序,但在索引上循环(我通常这样做是为了将数据复制到另一个表)时,似乎没有使用正确的排序索引

在我看来,这似乎是一个bug:groupby语句中的sort选项对结果没有影响,而且也有类似的报道

现在我的问题是:有没有简单的方法来解决这个问题?head语句似乎正确地给出了我的排序后的multindex数据帧,所以我一直在尝试复制这个head语句的输出

result = pipeinfoDF.head()
但这似乎不起作用

我最后一次尝试尝试根据重置的索引创建新的数据帧:

tmp = pipeinfoDF.copy()
tmp.reset_index(inplace=True)

lbls = tmp.Label.values
sds  = tmp.Side.values

pipeinfo_index2 = pd.MultiIndex.from_tuples(list(zip(lbls,sds)), names=mi_level_names)
pipeinfoDF2 = pd.DataFrame(index=pipeinfo_index2, columns=[])

for index, row in tmp.iterrows():
    for col in tmp.columns[2:]:
        pipeinfoDF2.ix[(row["Label"], row["Side"]), col] = row[col]
再次使用head()我得到了正确的结果

             Nc
Label Side     
yaki  B       1
      C       1
sdjks B      10
      C      10
ztest C     400
但是,对于前面的multindex帧上的循环,它再次对第一个组进行排序,我使用sort=False显式地阻止了这一点

for (label, df) in pipeinfoDF2.groupby(level=0, sort=False):
    side_list = df.index.get_level_values('Side')
    for side in side_list:
        data = pipeinfoDF2.ix[(label, side)]
        print(label, side, data.Nc)
这给

sdjks B 10.0
sdjks C 10.0
yaki B 1.0
yaki C 1.0
ztest C 400.0
ztest B 400.0
因此groupby选项似乎再次按照第一个索引排序

编辑:我发现以下内容可以修复此问题。如果打印数据框的索引,则其标签不按数字顺序排列:

print(pipeinfoDF2.index)

MultiIndex(levels=[['sdjks', 'yaki', 'ztest'], ['B', 'C']],
           labels=[[1, 1, 0, 0, 2, 2], [0, 1, 0, 1, 1, 0]],
           names=['Label', 'Side'])
这里的级别为“sdjks”、“yaki”、“ztest”,标签对应顺序为1,1,0,0,2,2 绘制第一个排序的pipeinfoDF的索引时也可以看到同样的情况,其中sort_索引保持多索引中级别的顺序,但只更改标签的顺序

因此,我可以通过强制标签以0,0,1,1,2,2的形式运行来解决问题,因为groupby显然会忽略标签的顺序,并且总是选择级别的顺序。因此,我的解决办法是

pipeinfo_index2 = pd.MultiIndex.from_tuples([tuples[0]], names=mi_level_names)
pipeinfoDF2 = pd.DataFrame(index=pipeinfo_index2, columns=[])
然后像以前一样填充其余的字段。通过这种方式,multindex看起来像

MultiIndex(levels=[['yaki', 'sdjks', 'ztest'], ['B', 'C']],
           labels=[[0, 0, 1, 1, 2, 2], [0, 1, 0, 1, 1, 0]],
           names=['Label', 'Side'])
现在使用groupby在行上循环给出以下输出

yaki B 1.0
yaki C 1.0
sdjks B 10.0
sdjks C 10.0
ztest C 400.0
ztest B 400.0
这是正确的

因此,我发现了一个非常糟糕的解决方法:在排序之后,将整个数据帧复制到一个新的数据帧,重置索引,然后将所有内容复制回,以强制多索引标签按数字顺序排列。但我认为这是非常低效的,并且会生成大量代码,我相信这是可能做到更高效的

因此,我的问题是:有没有一种方法可以在考虑标签顺序的多索引数据帧的行上循环?这显然被忽视了。我错过什么了吗?希望有一个更简单的方法来做到这一点

任何提示,谢谢

编辑:

Firelynx的建议有效。如果我这样做

for (label,side) in pipeinfoDF.index:
    data = pipeinfoDF.ix[(label, side)]
    print(label, side, data.Nc)
在第一次排序之后,我正确地按排序顺序获取数据

yaki B 1.0
yaki C 1.0
sdjks B 10.0
sdjks C 10.0
ztest C 400.0
ztest B 400.0
节省了我大量的编码。然而,剩下的问题是:如果groupby上的sort=False选项不能产生相同的结果吗?这是一个bug,还是我错过了使用groupby方法在数据帧上循环。它基于我在谷歌上搜索过的例子,但使用时应该小心。 无论如何,现在我解决了我的问题,我打算通过访问数据的方式放弃我的groupby

编辑:

Firelynx的解决方案是可行的,但是,它不再考虑多级结构,而是将所有标签和边级别放在一个列表中

为了得到与我想要使用groupby方法非常相似的东西,我现在做以下的hack

label_list = []
for (label,side) in pipeinfoDF.index:
    if not label in label_list:
        label_list.append(label)

for label in label_list:
    df = pipeinfoDF.loc[label]
    side_list = df.index.get_level_values('Side')
    for side in side_list:
        data = pipeinfoDF.ix[(label, side)]
        print(label, side, data.Nc)
正确的结果是

yaki B 1.0
yaki C 1.0
sdjks B 10.0
sdjks C 10.0
ztest C 400.0
ztest B 400.0
因此,我首先使用Firelynx的建议提取已排序的标签列表,然后循环遍历该列表以获得每个标签的边,并对其执行我想执行的操作。虽然这比我的第一个方法要干净得多,但我仍然觉得它可以更直接地完成。我无法想象您不能在排序的多索引数据帧上使用groupby方法而不扰乱排序顺序。也许有人有个建议?无论如何,现在我对这个解决方案很满意

基于Firelynx的最新建议,我有一个小的更新,使它更干净一点。不过,您仍然需要保留一个列表,以防止标签重复计数,因为unique仅适用于unique(标签,侧面)组合。所以我现在有

label_list = []
for (label, side) in pipeinfoDF.index.unique():
    if not label in label_list:
        label_list.append(label)
    else:
        continue
    df = pipeinfoDF.loc[label]
    side_list = df.index.get_level_values('Side')
    for side in side_list:
        data = pipeinfoDF.ix[(label, side)]
        print(label, side, data.Nc)

是否可以将unique()单独应用于标签?然后我可以删除标签列表以跟踪哪个标签已经被处理过

您的
for
循环将通过
.groupby(level=0,
您只是在
level=0
上进行分组,因此您生成的数据集将仅在索引的第一级进行排序

您可能可以:

for label in pipedinfoDF.index.unique():
    group = pipedinfoDF.loc[label]

要获得所需的顺序。

for循环将遍历
.groupby(level=0,
,您只是在level=0上分组,因此生成的数据集将仅在索引的第一级排序。您可能可以在pipedinfoDF.index.sort\u levels()中对标签执行
只需使用该标签访问分组对象即可获得所需的顺序。Firelynx,太棒了!您已经解决了我的问题!这很有效。尽管排序级别无法识别。因此我只需使用标签pipeinfoDF.index,然后我就可以按正确的顺序访问数据。非常感谢!