熊猫中的条件列选择
问题描述:
我想根据特定条件从DataFrame中选择列。我知道它可以用循环完成,但我的df非常大,所以效率至关重要。列选择的条件是只有non-nan条目或只有nans的序列,后跟一个只有non-nan条目的序列。熊猫中的条件列选择
下面是一个例子。请看下面的数据框:
pd.DataFrame([[1, np.nan, 2, np.nan], [2, np.nan, 5, np.nan], [4, 8, np.nan, 1], [3, 2, np.nan, 2], [3, 2, 5, np.nan]])
0 1 2 3
0 1 NaN 2.0 NaN
1 2 NaN 5.0 NaN
2 4 8.0 NaN 1.0
3 3 2.0 NaN 2.0
4 3 2.0 5.0 NaN
从的话,我想只选择列0和1。关于如何做到这一点没有有效循环有什么建议?
答
逻辑
- 计数每一列中的空值。如果唯一的空值在开头,那么列中空值的数量应该等于第一个有效索引的位置。
- 获取第一个有效索引
- 按空计数对索引进行分片并与第一个有效索引进行比较。如果它们相等,那么这就是一个很好的列
cnull = df.isnull().sum()
fvald = df.apply(pd.Series.first_valid_index)
cols = df.index[cnull] == fvald
df.loc[:, cols]
与速度提升
老答案
主编def pir1(df):
cnull = df.isnull().sum()
fvald = df.apply(pd.Series.first_valid_index)
cols = df.index[cnull] == fvald
return df.loc[:, cols]
使用快得多回答相同的逻辑
def pir2(df):
nulls = np.isnan(df.values)
null_count = nulls.sum(0)
first_valid = nulls.argmin(0)
null_on_top = null_count == first_valid
filtered_data = df.values[:, null_on_top]
filtered_columns = df.columns.values[null_on_top]
return pd.DataFrame(filtered_data, df.index, filtered_columns)
答
考虑一个DF
所示,其具有以各种可能的位置Nans
:
1.双方Nans
本:
通过用0和有限值与1的更换所有的NaN创建掩模:
mask = np.where(np.isnan(df), 0, 1)
采取它横跨每个对应的元素差柱。接下来,取其值。这里的逻辑是,每当每列中有三个唯一值时,则丢弃该列(即→-1,1,0),因为在这种情况下会有序列中断。
想法是取总和并创建一个子集,只要总和结果小于2的值。(因为在mod之后,我们得到1,1,0)。所以,对于极端情况,我们得到总和为2,这些列当然是不相交的,必须丢弃。
criteria = pd.DataFrame(mask, columns=df.columns).diff(1).abs().sum().lt(2)
最后转置DF
,并使用该条件,重新转置来获得具有另一个在一个仅Nans
部和有限值所需的结果。
df.loc[:, criteria]
2. Nans
存在于顶部:
mask = np.where(np.isnan(df), 0, 1)
criteria = pd.DataFrame(mask, columns=df.columns).diff(1).ne(-1).any()
df.loc[:, criteria]
+0
非常棒@NickiMaveli,它的速度比上面的解决方案快3倍。 – splinter
由于@piRSquared。这个解决方案确实完成了工作,但运行时间比下面发布的解决方案长3倍以上 – splinter
@splinter我并不感到惊讶。我想到尼基尔走的路线,但我选择了简洁。尼基提供了一个很好的答案。尽管使用相同的逻辑,我会更新我的文章,但利用一些技巧加快速度。 – piRSquared
听起来不错@piRSquared – splinter