pandas 如何将一个多索引行拆分为两个多索引行?

d4so4syb  于 2022-11-27  发布在  其他
关注(0)|答案(2)|浏览(120)

我有一个 Dataframe ,其中有多个层次的Multiindex。其中一个层次是latlon,它是一个数字串,中间有一个;。但是,为了进一步处理,有一个lat层次和一个lon层次更有意义。用浮点数表示数字,而不是组合字符串。
如何最好地将此级别划分为两个级别?
我有一个解决方案,但它似乎不是很 * Python *,需要建立一个新的数据框架,所以我正在寻找一个更好的方法。

MWE:

设置一个简单的测试df:

number = [1, 2, 3]
name = ['foo', 'bar', 'baz']
latlon = ['10.1;50.1', '12.2;52.2', '13.3;53.3']
idx = pd.MultiIndex.from_arrays([number, name, latlon], 
                                 names=('number','name', 'latlon'))
data = np.random.rand(4,3)
df = pd.DataFrame(data=data, columns=idx)

(原始数据在Multiindex中有10个级别,大小为25000, 750)正如您所看到的,latlon很容易让人阅读,但不是特别有用。我想要一个latlon级别,带有浮点数。
我想到的是:

# get a list of them, to iterate through
latlons = df.columns.get_level_values('latlon').to_list()
# set up emptly lists and start iterating
lats = []
lons = []
for i in latlons:
# do some string searches and split by positions
    start_str = i.find(';')+1 
    end_str = i.find('\n')
    lon_str = i[0:start_str-1]
    lon = float(lon_str)
    lons.append(lon)
    lat_str = i[start_str:end_str]
    lat = float(lat_str)
    lats.append(lat)

现在有两个列表,一个是lats,另一个是隆恩,它们可以用来建立一个新的索引,从而建立一个新的df:

number = df.columns.get_level_values('number').to_list()
# I can't reuse 'number' from the initial setup, since the original
# comes from an excel import, so I must extract it here.
name = df.columns.get_level_values('name').to_list()
idx = pd.MultiIndex.from_arrays([number, name, lats, lons], 
                                 names=('number','name', 'lat', 'lon'))
data = df.values
df2 = pd.DataFrame(data=data, columns=idx)

这是工作,是非常容易理解,但这一切都感觉非常hacky和一个hickup远离混淆数据。
有更简单/更好的方法吗?

wvt8vs2t

wvt8vs2t1#

我会暂时将MultiIndex转换为DataFrame,以便从DataFrame的方法中获益:

new_idx = pd.MultiIndex.from_frame(
 df.columns.to_frame()
   .pipe(lambda d: d.join(d.pop('latlon')
                           .str.split(';', expand=True)
                           .set_axis(['lat', 'lon'], axis=1)
                         ))
   .astype({'lat': float, 'lon': float})
)

df.columns = new_idx

输出量:

number         1         2         3
name         foo       bar       baz
lat         10.1      12.2      13.3
lon         50.1      52.2      53.3
0       0.796467  0.769194  0.733470
1       0.272247  0.558985  0.345007
2       0.209480  0.669443  0.648002
3       0.466146  0.262006  0.236987
osh3o9ms

osh3o9ms2#

提取索引、拆分和重建索引:

arr = df.columns
arrays = [arr.get_level_values(num) for num in range(arr.nlevels)]
*arrays, latlon = arrays
latlon = latlon.str.split(';')
lon = latlon.str[-1].astype(float).rename('lon')
lat = latlon.str[0].astype(float).rename('lat')
arrays.extend([lat,lon])
df.columns = pd.MultiIndex.from_arrays(arrays)
df
number         1         2         3
name         foo       bar       baz
lat         10.1      12.2      13.3
lon         50.1      52.2      53.3
0       0.469529  0.356716  0.287799
1       0.786352  0.557752  0.318536
2       0.877670  0.503199  0.225858
3       0.324959  0.253091  0.967328

相关问题