pandas 如何保持每个索引一列的值?

oalqel3c  于 2023-04-19  发布在  其他
关注(0)|答案(3)|浏览(116)

考虑以下Pandas dataframe:

col_a  col_b  col_c
0   10     15     20
0   10     15     20
1   10     15     20
1   10     15     20
1   10     15     20
1   10     15     20
2   10     15     20

现在,让我们考虑我们想要以下Map:

{
  0: 'col_a',
  1: 'col_b',
  2: 'col_c'
}

Map本质上决定了我们应该为每个索引保留哪一列!
输出df

column
0   10
0   10
1   15
1   15
1   15
1   15
2   20

到目前为止,我有这样的东西:

keep_cols = [(0, 'col_a'), (1, 'col_b'), (2, 'col_c')]

output = pd.concat([df.loc[df['index_col'] == idx, col] for idx, col in keep_cols], axis=1)

然而,我在实际连接它们之前创建了子dfs,我想就性能而言,这是次优的!

fnx2tebb

fnx2tebb1#

map使用索引查找:

mapper = {
  0: 'col_a',
  1: 'col_b',
  2: 'col_c'
}

idx, cols = pd.factorize(df.index.map(mapper))

df['column'] = df.reindex(cols, axis=1).to_numpy()[np.arange(len(df)), idx]

输出:

col_a  col_b  col_c  column
0     10     15     20      10
0     10     15     20      10
1     10     15     20      15
1     10     15     20      15
1     10     15     20      15
1     10     15     20      15
2     10     15     20      20

如果要将Series或新DataFrame作为输出:

out = pd.Series(df.reindex(cols, axis=1).to_numpy()[np.arange(len(df)), idx], index=df.index)

# or
out = pd.DataFrame({'column': df.reindex(cols, axis=1).to_numpy()[np.arange(len(df)), idx]}, index=df.index)

输出:

# Series
0    10
0    10
1    15
1    15
1    15
1    15
2    20
dtype: int64

# DataFrame
   column
0      10
0      10
1      15
1      15
1      15
1      15
2      20
替代

为了好玩,这里有另一个使用stack的替代方法,如果每行只有一个匹配:

# stack the dataframe
s = df.stack()

# identify the matches
m = s.index.get_level_values(0).map(mapper) == s.index.get_level_values(1)

# keep only the matches
out = s[m].droplevel(1)

输出:

0    10
0    10
1    15
1    15
1    15
1    15
2    20
dtype: int64
限制

如果你的索引没有匹配,factorize将返回-1,这将被错误地Map,你应该用途:

idx, cols = pd.factorize(df.index.map(mapper))

df['column'] = np.where(idx>=0,
                        df.reindex(cols, axis=1).to_numpy()[np.arange(len(df)), idx],
                        np.nan)

如果使用另一种解决方案,您将无法使用reindexs[m].droplevel(1).reindex(df.index)),因为您有重复的索引,这将引发错误。
示例:

col_a  col_b  col_c  column
0     10     15     20    10.0
0     10     15     20    10.0
1     10     15     20    15.0
1     10     15     20    15.0
1     10     15     20    15.0
1     10     15     20    15.0
2     10     15     20    20.0
3      6      7      8     NaN
7vux5j2d

7vux5j2d2#

使用Index.map通过索引/列标签查找值:

d = {
  0: 'col_a',
  1: 'col_b',
  2: 'col_c'
}

idx, cols = pd.factorize(df.index.map(d))
df['column'] = df.reindex(cols, axis=1).to_numpy()[np.arange(len(df)), idx]

或者使用rename

idx, cols = pd.factorize(df.rename(d).index)
df['column'] = df.reindex(cols, axis=1).to_numpy()[np.arange(len(df)), idx]
print (df)
   col_a  col_b  col_c  column
0     10     15     20      10
0     10     15     20      10
1     10     15     20      15
1     10     15     20      15
1     10     15     20      15
1     10     15     20      15
2     10     15     20      20

对于传递给DataFrame构造函数的一列DataFrame:

d = {
  0: 'col_a',
  1: 'col_b',
  2: 'col_c'
}

idx, cols = pd.factorize(df.rename(d).index)
arr = df.reindex(cols, axis=1).to_numpy()[np.arange(len(df)), idx]

df = pd.DataFrame({'column':arr}, index=df.index)
print (df)
   column
0      10
0      10
1      15
1      15
1      15
1      15
2      20
kse8i1jr

kse8i1jr3#

另一种可能的解决方案:

pd.DataFrame(np.hstack([np.array(df.loc[y]) for y in zip(d.keys(), d.values())]),
             index=df.index, columns=['col'])

输出:

col
0   10
0   10
1   15
1   15
1   15
1   15
2   20

相关问题