python - 转置 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
。
我怎样才能做到这一点?
笔记:
- 我的数据框很大。它包含近百万行,超过 15 个
Word*
类型列和超过 115 个C*
类型列(word*
并且C*
是我在示例中使用的列名)。 - 我
Python 2.7
用Pandas 0.17
.
解决方案
实际上,您的任务不是转置,而是类似于stack之类的东西,仅限于非零值,并添加了一些内容,即对于包含全零的行(在C1到C4中),您希望输出包含word1到word3的值,并且:
- 变量 == 'C1' ,
- 值 == 0。
为此,请计算 2 个中间变量:
包含C1到C4列 的堆栈的系列,word1到word3移动到索引,索引的最后一级重命名为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
包含全零的行的输出结果(在C1到C4中):
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()
,一切都应该清楚。
推荐阅读
- android - 为什么我的 android 应用程序因新意图而崩溃,而没有任何错误日志?
- tarantool - 如何在 Tarantool 中使用自增索引?
- php - Yii2 - 只有一个选择获取选项
- sql - 查找重复项
- android - 如何在应用更新中模拟 onFailureListener & resultCode != Activity.RESULT_OK?
- javascript - React:函数在获取完成之前返回
- html - Ruby On Rails - 用 HTML 表单替换 URL 中的文本
- c# - C# 中的三元运算符,具有 3 个条件
- python - 无法在我的 jupyter 笔记本上安装 scikit-surprise
- python - Python 遍历 Pandas DataFrame 并添加使用 geopy.geocoders Nominatim 性能建议计算的新值