python - Pandas 在多索引中连接级别

标签 python pandas dataframe

我有以下 Excel 文件:

enter image description here

{0: {0: nan, 1: nan, 2: nan, 3: 'A', 4: 'A', 5: 'B', 6: 'B', 7: 'C', 8: 'C'},
 1: {0: nan, 1: nan, 2: nan, 3: 1.0, 4: 2.0, 5: 1.0, 6: 2.0, 7: 1.0, 8: 2.0},
 2: {0: 'AA1', 1: 'a', 2: 'ng/mL', 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1},
 3: {0: 'AA2', 1: 'a', 2: nan, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1},
 4: {0: 'BB1', 1: 'b', 2: nan, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1},
 5: {0: 'BB2', 1: 'b', 2: 'mL', 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1},
 6: {0: 'CC1', 1: 'c', 2: nan, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1},
 7: {0: 'CC2', 1: 'c', 2: nan, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1}}

我想创建以下数据框:

level_0     AA1   AA2   CB1  BB2   CC1   CC2
new     a ng/mL a N/A b N/A b mL c N/A c N/A
0 1                                         
A 1           1     1     1    1     1     1
  2           1     1     1    1     1     1
B 1           1     1     1    1     1     1
  2           1     1     1    1     1     1
C 1           1     1     1    1     1     1
  2           1     1     1    1     1     1

我尝试过的:

# read the column index separately to avoid pandas inputting "Unnamed: ..."
# for the nans
df = pd.read_excel(file_path, skiprows=3, index_col=None, header=None)
df.set_index([0, 1], inplace=True)

# the column index
cols = pd.read_excel(file_path, nrows=3, index_col=None, header=None).loc[:, 2:]
cols = cols.fillna('N/A')
idx = pd.MultiIndex.from_arrays(cols.values)
df.columns = idx

新数据框:

      AA1 AA2 CB1 BB2 CC1 CC2
        a   a   b   b   c   c
    ng/mL N/A N/A  mL N/A N/A
0 1                          
A 1     1   1   1   1   1   1
  2     1   1   1   1   1   1
B 1     1   1   1   1   1   1
  2     1   1   1   1   1   1
C 1     1   1   1   1   1   1
  2     1   1   1   1   1   1

这种方法有效,但有点乏味:

df1 = df.T.reset_index()
df1['new'] = df1.loc[:, 'level_1'] + ' ' + df1.loc[:, 'level_2']
df1.set_index(['level_0', 'new']).drop(['level_1', 'level_2'], axis=1).T

这给了我:

level_0     AA1   AA2   CB1  BB2   CC1   CC2
new     a ng/mL a N/A b N/A b mL c N/A c N/A
0 1                                         
A 1           1     1     1    1     1     1
  2           1     1     1    1     1     1
B 1           1     1     1    1     1     1
  2           1     1     1    1     1     1
C 1           1     1     1    1     1     1
  2           1     1     1    1     1     1

是否有更简单的解决方案?

最佳答案

用途:

#file from sample data

d = {0: {0:  np.nan, 1:  np.nan, 2:  np.nan, 3: 'A', 4: 'A', 5: 'B', 6: 'B', 7: 'C', 8: 'C'}, 
     1: {0:  np.nan, 1:  np.nan, 2:  np.nan, 3: 1.0, 4: 2.0, 5: 1.0, 6: 2.0, 7: 1.0, 8: 2.0}, 
     2: {0: 'AA1', 1: 'a', 2: 'ng/mL', 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1}, 
     3: {0: 'AA2', 1: 'a', 2:  np.nan, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1}, 
     4: {0: 'BB1', 1: 'b', 2:  np.nan, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1}, 
     5: {0: 'BB2', 1: 'b', 2: 'mL', 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1}, 
     6: {0: 'CC1', 1: 'c', 2:  np.nan, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1}, 
     7: {0: 'CC2', 1: 'c', 2:  np.nan, 3: 1, 4: 1, 5: 1, 6: 1, 7: 1, 8: 1}}

df = pd.DataFrame(d)

df.to_excel('file.xlsx', header=False, index=False)

首先使用 header=[0,1,2] 创建 MultiIndex DataFrame,然后使用 DataFrame.set_index 的前 2 列创建 MultiIndex并通过 DataFrame.reset_index 删除索引名称:

df = pd.read_excel('file.xlsx', header=[0,1,2])

df = df.set_index(df.columns[:2].tolist()).rename_axis((None, None))

然后循环列表理解中的每个级别,如果不是未命名,则将第二个级别与第三个级别连接起来,最后使用 MultiIndex.from_tuples :

tuples = [(a, f'{b} N/A') if c.startswith('Unnamed') 
          else (a, f'{b} {c}') 
          for a, b, c in df.columns]

print (tuples)
[('AA1', 'a ng/mL'), ('AA2', 'a N/A'), 
 ('BB1', 'b N/A'), ('BB2', 'b mL'),
 ('CC1', 'c N/A'), ('CC2', 'c N/A')]

df.columns = pd.MultiIndex.from_tuples(tuples)
print (df)
        AA1   AA2   BB1  BB2   CC1   CC2
    a ng/mL a N/A b N/A b mL c N/A c N/A
A 1       1     1     1    1     1     1
  2       1     1     1    1     1     1
B 1       1     1     1    1     1     1
  2       1     1     1    1     1     1
C 1       1     1     1    1     1     1
  2       1     1     1    1     1     1

另一个想法是使用:

df = pd.read_excel('file.xlsx', header=[0,1,2])
df = df.set_index(df.columns[:2].tolist()).rename_axis((None, None))

lv1 = df.columns.get_level_values(0)
lv2 = df.columns.get_level_values(1)
lv3 = df.columns.get_level_values(2)
lv3 = lv3.where(~lv3.str.startswith('Unnamed'),'N/A')

df.columns = [lv1, lv2.to_series() + ' ' + lv3]

关于python - Pandas 在多索引中连接级别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57411679/

相关文章:

python - 从另一个数据帧创建一个数据帧(使用数据透视)

python - 根据日期和时间分割数据

python - 写入文件错误和权限错误

python - 使用python的U盘盘符

python - Pandas Groupby nlargest(唯一的 nlargest)

r - R 建模中的数据整理

在函数中返回不同的数据帧 - R

python - 在带有 Google Cloud 服务的 Python 中使用多处理时出现 SSL 错误

python - Pandas groupby 列并乘以聚合函数中的其他两列

python - 如何使用 Pandas 从文件中提取 html 表格?