首页 > 解决方案 > 转置 Pandas 数据帧,但仅保留非零值

问题描述

数据框:

让我澄清一下我的问题。我的pandas.DataFrame长相是这样 的

data = [
    ['word11', 'word12', 'word13', 'word14', 0, 0, 0, 0, 0],
    ['word21', 'word22', 'word23', 'word24', 0, -3, 34, 0, 0],
    ['word31', 'word32', 'word33', 'word34', 0, 1.6, 0, 0, 0],
    ['word41', 'word42', 'word43', 'word44', 0, 0, 0, 0, 0]
]

df = pd.DataFrame(data, columns=['word1', 'word2', 'word3', 'word4', 'C1', 'C2', 'C3', 'C4', 'C5'])

要生成的输出:

由此,我想得到一个看起来像的数据框

    word1   word2   word3   word4  C1   C2  C3  C4  C5
0  word11  word12  word13  word14   0  0.0   0   0   0
1  word21  word22  word23  word24   0 -3.0  34   0   0
2  word31  word32  word33  word34   0  1.6   0   0   0
3  word41  word42  word43  word44   0  0.0   0   0   0

我的程序:

这是我为获取上述数据框所做的工作

primary_columns = ['word1', 'word2', 'word3', 'word4']
transposing_columns = ['C1', 'C2', 'C3', 'C4', 'C5']
transposed_df = df.melt(id_vars=primary_columns, value_vars=transposing_columns)
compare_columns = primary_columns + ['value']

然后我根据“值”列的值将数据框分成两部分并删除重复项。

nonzero_df = transposed_df[transposed_df['value'] != 0]
zero_df = transposed_df[transposed_df['value'] == 0]
zero_df = zero_df.drop_duplicates(subset=compare_columns, keep='first')
df = nonzero_df.append(zero_df)

这给了我以下输出

df = df.reset_index(drop=True)
df

    word1   word2   word3   word4 variable  value
0  word21  word22  word23  word24       C2   -3.0
1  word31  word32  word33  word34       C2    1.6
2  word21  word22  word23  word24       C3   34.0
3  word11  word12  word13  word14       C1    0.0
4  word21  word22  word23  word24       C1    0.0
5  word31  word32  word33  word34       C1    0.0
6  word41  word42  word43  word44       C1    0.0

问题:

我不想看到df.iloc[4]df.iloc[5]

如果word1, word2,word3和 的值word4相同,但差异仅在value列中,则保留具有非零值的行并删除具有 0 值的行。我不在乎 column 的值variable

我怎样才能做到这一点?

笔记:

  1. 我的数据框很大。它包含近百万行,超过 15 个 Word*类型列和超过 115 个 C*类型列(word*并且C*是我在示例中使用的列名)。
  2. Python 2.7Pandas 0.17.

标签: pythonpandasdataframe

解决方案


实际上,您的任务不是转置,而是类似于stack之类的东西,仅限于非零值,并添加了一些内容,即对于包含全零的行(在C1C4中),您希望输出包含word1word3的值,并且:

  • 变量 == 'C1' ,
  • 值 == 0

为此,请计算 2 个中间变量:

  1. 包含C1C4列 的堆栈的系列word1word3移动到索引,索引的最后一级重命名为variable

    s = df.set_index(['word1', 'word2', 'word3']).stack().rename('value')
    s.index.rename('variable', level=3, inplace=True)
    

    对于您的输入数据,结果是:

    word1   word2   word3   variable
    word11  word12  word13  C1          0
                            C2          0
                            C3          0
                            C4          0
    word21  word22  word23  C1          0
                            C2          1
                            C3          1
                            C4          0
    word31  word32  word33  C1          1
                            C2          0
                            C3          0
                            C4          1
    Name: value, dtype: int64
    
  2. 包含全零的行的输出结果(在C1C4中):

    dfZer = df[df.loc[:, 'C1':'C4'].sum(axis=1) == 0].loc[:, 'word1':'word3']\
       .assign(variable='C1', value=0)
    

    对于您的数据,结果是:

        word1   word2   word3 variable  value
    0  word11  word12  word13       C1      0
    

然后生成最终结果为:

pd.concat([s[s > 0].reset_index(), dfZer], sort=False, ignore_index=True)

注意:

  • s[s > 0]删除值为0的元素,
  • reset_index()将其转换回 DataFrame,
  • dfZer提供“全零”输入行的结果,
  • ignore_index=True“重新生成”结果中的索引。

要跟踪此解决方案的工作原理,请同时打印s[s > 0].reset_index() ,一切都应该清楚。


推荐阅读