【问题标题】:Adding a new index row to an existing dataframe and sorting by it向现有数据框添加新的索引行并按其排序
【发布时间】:2016-02-16 18:23:15
【问题描述】:

我有一个大熊猫数据框,其中包含时间序列数据和相当大的多索引。所述索引包含有关时间序列的各种信息,例如位置、数据类型等。

现在我想在索引中添加一个新行,带有一个整数(或浮点数,并不重要),包含到某个点的距离。之后,我想按这个距离对数据框进行排序。

我不确定如何添加新的索引级别,以及如何手动分配新值。此外,pandas 甚至可以在其索引级别之一中对随机数之后的列进行排序吗?

示例

(来自here的代码)

header=pd.MultiIndex.from_product([['location1','location2'],['S1','S2','S3']],names=['loc','S'])
df = pd.DataFrame(np.random.randn(5, 6), index=['a','b','c','d','e'], columns = header)

看起来像这样:

loc  location1                      location2                    
S           S1        S2        S3         S1        S2        S3
a     1.530590  0.536364  1.295848   0.422256 -1.853786  1.334981
b     0.275857 -0.848685 -1.212584  -0.464235 -0.855600  0.680985
c    -1.209607  0.265359 -0.695233   0.643896  1.315216 -0.751027
d    -1.591613 -0.178605  0.878567   0.647389 -0.454313 -1.972509
e     1.098193 -0.766810  0.087173   0.714301 -0.886545 -0.826163

我想要做的是,在第一步中,为每列添加一些距离,例如location1 S1 add dist 200location1 S2 add dist 760 等等,结果如下:

loc  location1                      location2                    
S           S1        S2        S3         S1        S2        S3
dist       200       760        10       1000       340        70
a     1.530590  0.536364  1.295848   0.422256 -1.853786  1.334981
b     0.275857 -0.848685 -1.212584  -0.464235 -0.855600  0.680985
c    -1.209607  0.265359 -0.695233   0.643896  1.315216 -0.751027
d    -1.591613 -0.178605  0.878567   0.647389 -0.454313 -1.972509
e     1.098193 -0.766810  0.087173   0.714301 -0.886545 -0.826163

然后执行df.sortlevel('dist')之类的操作,结果

loc location1 location2 location1 location2 location1 location2
S          S3        S3        S1        S2        S2        S1
dist       10        70       200       340       760      1000
a    1.295848  1.334981  1.530590 -1.853786  0.536364  0.422256
b   -1.212584  0.680985  0.275857 -0.855600 -0.848685 -0.464235
…

这样整个事情就按距离排序,比如plt.matshow(df.corr())

pandas 甚至可以在带有整数的随机索引之后对 df 进行排序吗?因为我有另一个数据框,它的多重索引中已经有一个整数,这里some_otherdf.sortlevel('HZB') 结果为TypeError: can only sort by level with a hierarchical index

编辑:

到目前为止,有两个答案,对于我的测试用例来说,这两个答案都非常好。 我认为@Pedro M Duarte 的答案可能是更正确的答案,因为它按预期使用了多索引。但是,对于我的真实数据,对于 7 级深度的多索引和 50 个数据系列,它需要大量的返工或大量输入,这很容易出错。 @Nader Hisham 忽略了我保留在我的多索引中的请求,但它只需要快速、简单和容易地检查一行简单数字的写入(为我节省了很多时间),然后我可以在排序后将其删除。 对于有类似问题的其他人,可能会有所不同。

【问题讨论】:

    标签: python sorting pandas indexing multi-index


    【解决方案1】:
    In[1]:
    import pandas as pd
    import numpy as np
    
    header=pd.MultiIndex.from_product(
        [['location1','location2'],['S1','S2','S3']],
        names=['loc','S'])
    
    df = pd.DataFrame(np.random.randn(5, 6), 
                      index=['a','b','c','d','e'], columns = header)
    
    print(df)
    
    Out[1]:
        loc location1                     location2                    
        S          S1        S2        S3        S1        S2        S3
        a    0.503357 -0.461202 -1.412865  0.866237  1.290292  0.635869
        b   -0.904658 -1.190422 -0.198654 -0.916884 -1.070291 -1.918091
        c   -1.448068 -0.121475 -0.838693  0.047861 -0.131904  1.154370
        d    1.758752 -0.094962 -2.035204 -0.399195 -0.756726  1.609393
        e    0.421521  1.134518 -0.809148 -0.543523 -1.161328  1.261901
    
    
    
    In[2]:
    distances = {
        ('location1','S1'): 200,
        ('location1','S2'): 760,
        ('location1','S3'): 10,
        ('location2','S1'): 1000,
        ('location2','S2'): 340,
        ('location2','S3'): 70,
    }
    
    index = df.columns
    df.columns = pd.MultiIndex.from_tuples(
        [(key[0], key[1], distances[key],) for key in index.get_values()],
        names=[index.get_level_values(0).name,
               index.get_level_values(1).name,
               'dist']
    )
    print(df)
    
    Out[2]:
        loc  location1                     location2                    
        S           S1        S2        S3        S1        S2        S3
        dist      200       760       10        1000      340       70  
        a     0.503357 -0.461202 -1.412865  0.866237  1.290292  0.635869
        b    -0.904658 -1.190422 -0.198654 -0.916884 -1.070291 -1.918091
        c    -1.448068 -0.121475 -0.838693  0.047861 -0.131904  1.154370
        d     1.758752 -0.094962 -2.035204 -0.399195 -0.756726  1.609393
        e     0.421521  1.134518 -0.809148 -0.543523 -1.161328  1.261901
    
    
    
    In[3]:
    result = df.sortlevel(level=2, axis=1)
    print(result)
    
    Out[3]:
        loc  location1 location2 location1 location2 location1 location2
        S           S3        S3        S1        S2        S2        S1
        dist      10        70        200       340       760       1000
        a    -1.412865  0.635869  0.503357  1.290292 -0.461202  0.866237
        b    -0.198654 -1.918091 -0.904658 -1.070291 -1.190422 -0.916884
        c    -0.838693  1.154370 -1.448068 -0.131904 -0.121475  0.047861
        d    -2.035204  1.609393  1.758752 -0.756726 -0.094962 -0.399195
        e    -0.809148  1.261901  0.421521 -1.161328  1.134518 -0.543523
    

    【讨论】:

    • 看起来不错。我必须对它进行一些尝试,看看我是否可以让它适应我的真实数据。您能否详细说明df.columns = pd.MultiIndex.from_tuples( [(key[0], key[1], distances[key],) for key in index.get_values()], names=[index.get_level_values(0).name, index.get_level_values(1).name, 'dist'] ) 部分?我不是 100% 确定它到底是做什么的。
    • 该行的重点是从头开始创建MultiIndex,保留原始index 的级别值并为dist 添加一个新级别。我正在为MultiIndex 使用from_tuples 构造函数。您必须向它传递一个元组列表,其中每个元组包含索引中条目的信息。您还传递了names,它将用于设置级别名称。在这种情况下,所需的MultiIndex 具有三个级别,因此元组列表中的每个元组都有len==3,就像names 列表一样。
    • 为了创建from_tuples 中所需的元组列表,我使用了列表推导,遍历index.get_values()。这里index.get_values() 为我们提供了原始MultiIndex 的方便表示,作为tuples 的列表。由于原来的MultiIndex 有两个级别,我可以通过key[0]key[1] 访问这些值。
    【解决方案2】:
    In [35]:
    df.loc['dist' , : ] = [200,760,10,1000,340,70]
    df
    Out[35]:
    loc                location1                 location2
    S     S1              S2            S3            S1          S2    S3
    a     0.348766  -0.326088   -0.891929   -0.704856   -1.514304   0.611692
    b    -0.546026  -0.111232   -1.022104   -1.246002   0.328385    0.576465
    c    -0.743512  -0.362791   -0.617021   -0.859157   -0.300368   0.292980
    d     0.090178  1.369648    0.171753    -0.411466   0.478654    1.814878
    e    -0.380414  -1.568492   -0.432858   1.034861    -0.633563   1.403627
    dist 200.000000 760.000000  10.000000   1000.000000 340.000000  70.000000
    
    
    In [36]:
    order = np.argsort(df.loc['dist' , :]).values
    order
    Out[36]:
    array([2, 5, 0, 4, 1, 3], dtype=int64)
    
    In [37]:
    
    df.iloc[: , order]
    Out[37]:
    loc    location1    location2   location1   location2   location1   location2
    S            S3      S3            S1         S2          S2           S1
    a     -0.891929    0.611692     0.348766    -1.514304   -0.326088   -0.704856
    b     -1.022104    0.576465    -0.546026    0.328385    -0.111232   -1.246002
    c     -0.617021    0.292980    -0.743512    -0.300368   -0.362791   -0.859157
    d     0.171753     1.814878     0.090178    0.478654    1.369648    -0.411466
    e     -0.432858    1.403627     -0.380414   -0.633563   -1.568492   1.034861
    dist  10.000000    70.000000    200.000000  340.000000  760.000000  1000.000000
    

    如果您想将 dist 索引作为第一个索引,您可以执行以下操作

    【讨论】:

    • 您只是将新的dist 行添加到数据框的数据部分,而不是索引。我不确定这是否不会给我带来诸如绘制系列之类的问题。会玩一下。
    • 是的,但它是ab 等索引,而不是locS 等多索引的一部分。当我执行df.plot() 时,它还会显示dist 部分。
    • 好的,我可以按照你的方式进行,排序后,删除droppeddf = dfordered.drop('dist') 行以获得正确的绘图。看起来有点老套,但可能比 Pedro M Duarte 的解决方案更快。我会玩一下,看看哪个最适合我。
    • 我会指出,我拍摄的是一般性而不是速度。请注意,我使用字典从locS 的值中获取dist 的值。在您的应用程序中,也许您有一个计算 dist 的函数,您可以插入该函数而不是我使用的字典。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-08
    • 2016-11-03
    相关资源
    最近更新 更多