Misalkan saya memiliki pandas DataFrame yang terlihat mirip dengan struktur berikut. Namun dalam praktiknya mungkin jauh lebih besar dan jumlah indeks level 1, serta jumlah indeks level 2 (per indeks level 1) akan bervariasi, jadi solusinya tidak boleh membuat asumsi tentang ini:

index = pandas.MultiIndex.from_tuples([
    ("a", "s"),
    ("a", "u"),
    ("a", "v"),
    ("b", "s"),
    ("b", "u")])

result = pandas.DataFrame([
    [1, 2],
    [3, 4],
    [5, 6],
    [7, 8],
    [9, 10]], index=index, columns=["x", "y"])

Yang terlihat seperti ini:

      x   y
a s   1   2
  u   3   4
  v   5   6
b s   7   8
  u   9  10

Sekarang katakanlah saya ingin membuat baris "total" untuk setiap level "a" dan "b". Jadi mengingat hal di atas sebagai input, saya ingin kode saya menghasilkan sesuatu seperti ini:

      x   y
a s   1   2
  u   3   4
  v   5   6
  t   9  12
b s   7   8
  u   9  10
b t  16  18

Inilah kode yang saya miliki sejauh ini:

# Calculate totals
for level, _ in result.groupby(level=0):

    # work out the global total for that desk:
    x_sum = result.loc[level]["x"].sum()
    y_sum = result.loc[level]["y"].sum()

    result = result.append(pandas.DataFrame([[x_sum, y_sum]], columns=result.columns, index=pandas.MultiIndex.from_tuples([(level, "t")])))

Tetapi ini menghasilkan kolom "total" yang ditambahkan ke akhir:

      x   y
a s   1   2
  u   3   4
  v   5   6
b s   7   8
  u   9  10
a t   9  12
b t  16  18

Mengurutkan menggunakan result.sort_index() juga tidak melakukan apa yang saya inginkan:

      x   y
a s   1   2
  t   9  12
  u   3   4
  v   5   6
b s   7   8
  t  16  18
  u   9  10

Apa yang saya lakukan salah?

5
quant 10 Agustus 2017, 12:45

2 jawaban

Jawaban Terbaik

Ini benar-benar menjengkelkan, tetapi alasan untuk sorted Multiindex adalah kinerja yang lebih baik. Juga jika tidak diurutkan MultiIndex dimungkinkan beberapa UnsortedIndexError jika perlu pilih dengan MultiIndex.

Tetapi jika benar-benar perlu mengubah posisi label, gunakan reindex.

df = result.groupby(level=0).sum()
df.index = [df.index, ['t'] * len(df.index)]
df1 = pd.concat([result, df]).sort_index().reindex(['s','u','t'], level=1)

df1 = pd.concat([result, df]).sort_index()
print (df1)
      x   y
a s   1   2
  t   4   6
  u   3   4
b s   5   6
  t  12  14
  u   7   8

df1 = df1.reindex(['s','u','t'], level=1)
print (df1)
      x   y
a s   1   2
  u   3   4
  t   4   6
b s   5   6
  u   7   8
  t  12  14

Solusi yang lebih dinamis:

print (result.index.get_level_values(1).unique().tolist())
['s', 'u']

df1 = df1.reindex(result.index.get_level_values(1).unique().tolist() + ['t'], level=1)
print (df1)
      x   y
a s   1   2
  u   3   4
  t   4   6
b s   5   6
  u   7   8
  t  12  14

Solusi lain dengan pengaturan dengan pembesaran di kustom fungsi dengan GroupBy.apply< /a>:

def f(x):
    x.loc[(x.name, 't'),:] = x.sum()
    return x   

df = result.groupby(level=0, group_keys=False).apply(f)
print (df)
        x     y
a s   1.0   2.0
  u   3.0   4.0
  t   4.0   6.0
b s   5.0   6.0
  u   7.0   8.0
  t  12.0  14.0
2
jezrael 10 Agustus 2017, 11:08
result.reindex(pandas.MultiIndex.from_tuples([
("a", "s"),
("a", "u"),
("a", "t"),
("b", "s"),
("b", "u"),
("b", "t")
]))

Memberi saya

        x   y
a   s   1   2
    u   3   4
    t   4   6
b   s   5   6
    u   7   8
    t   12  14
0
wl2776 10 Agustus 2017, 09:53