我有一个62列的数据框,大部分都是空的。某些记录具有多个具有非空值的列,而其他记录只有一个非空值。我想知道是否有办法使用.dropna或其他策略返回最少行数,每列至少有一个非空值。
简化示例
a b c
NaN 1 NaN
1 NaN NaN
NaN NaN NaN
NaN 1 1
会返回
a b c
1 NaN NaN
NaN 1 1
...
答案 0 :(得分:5)
这是一个简单的贪婪解决方案,可以完成这项工作,但不能保证你拥有最少的行数(因为@chthonicdaemon说问题是NP难的)
import pandas as pd
import numpy as np
# sample dataframe
df = pd.DataFrame({'a':[np.nan,1,np.nan,np.nan],'b':[1, np.nan, np.nan, 1],'c':[np.nan, np.nan, np.nan, 1]})
df_orig = df
cols = df.columns.tolist()
rows = []
while not df.empty:
## Find the row with most non-null column entries
x = df.notnull().sum(axis=1).idxmax() # edit - fix for null/nonnull
## Add the row to our list and continue
rows.append(x)
## Remove the columns from our dataframe
df = df.drop(columns=df.columns[df.loc[[x]].notnull().any()].tolist())
## Access the dataframe with only 'essential' rows
df_orig.loc[rows]
输出:
a b c
3 NaN 1.0 1.0
1 1.0 NaN NaN
答案 1 :(得分:1)
我创建了一个对NaN
进行大量过滤的函数,但它也不保证最小行数。实际上,Brendan Frick answer总是返回较少的行。这个更注重性能。
这个想法基本上是计算非空值的数量,并对数据帧进行切片,使其达到计数阈值。如果切片的数据帧满足至少一个非空值的条件,则返回,否则,修改阈值。
def custom_dropna(df):
counts=df.count(axis=1)
for i in sorted(set(counts.values),reverse=True):
dropped_df = df[counts>=i]
if dropped_df.count().min()>=1:
return dropped_df
为了检查函数是否有效以及它是如何工作的,我生成了一个随机输入数据帧,并为df的不同属性执行了函数。
df = pd.DataFrame(np.random.choice([np.nan,1],size=(500,62),p=[.2,.8]),columns=range(62))
custom_dropna(df).count().values
# returned a dataframe with 3 rows
# [3 3 3 3 2 3 3 3 3 3 3 3 3 2 3 3 3 3 3 2 3 3 3 3 3 3 2 3 3 3 3 2 3 3 3 2 3
# 3 3 3 3 3 3 3 1 3 3 3 3 2 2 2 3 3 2 3 3 1 3 2 3 3]
# 631 µs ± 9.53 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
answer_Brendan_Frick(df).count().values
# returned 2 rows
# [1 2 2 2 1 1 1 2 2 2 2 2 2 2 2 1 2 2 2 1 2 2 2 2 2 1 2 2 2 2 1 1 1 1 2 2 2
# 2 2 1 1 2 2 2 1 1 1 2 2 1 2 1 1 2 2 2 2 2 1 2 2 1]
# 3 ms ± 8.19 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
我重复了5次时间和代码执行。 custom_dropna
返回2到5行,而answer_Brendan_Frick
总是返回2。每次重复的执行时间基本相同,分别为.6-.7 ms和2.9-3.1 ms。
custom_dropna(df).count().values
# returned 12 rows
# [2 4 5 4 4 3 5 3 4 3 2 8 6 5 4 2 5 4 6 8 6 2 5 5 6 4 3 1 4 4 4 4 6 7 4 3 4
# 5 3 4 3 1 4 3 1 6 3 2 6 6 4 4 4 5 5 5 3 4 4 6 5 4]
# 1.96 ms ± 34.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
answer_Brendan_Frick(df).count().values
# returned 6 rows
# [1 2 2 1 2 1 1 3 1 1 1 2 3 1 1 1 2 2 2 3 3 2 2 2 1 2 2 1 1 2 2 1 1 1 3 1 2
# 1 1 1 4 2 2 1 2 2 1 1 1 2 2 2 1 2 2 1 2 2 1 1 1 2]
# 8.21 ms ± 148 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
我重复了5次时间和代码执行。 custom_dropna
返回7到13行,而answer_Brendan_Frick
总是返回6。每次重复的执行时间基本相同,分别为1.5-2 ms和8.1-8.3 ms。
在这种情况下,custom_dropna
返回7到23行,而answer_Brendan_Frick
总是返回5。每次重复的执行时间基本相同,分别为2.4-2.7 ms和14.3-14.5 ms。
custom_dropna
返回的大量行是由于许多行具有相同的计数值,对于大型数据帧来说这将变得更糟。