我有以下数据帧:
df= pd.DataFrame({'A': np.random.randn(10),
'B': np.concatenate((np.repeat(np.nan, 4), np.array([0.7]), np.repeat(np.nan, 4), np.array([0.5]))),
'C': np.random.randn(10),
'D': np.concatenate((np.repeat(np.nan, 4), np.array([0.2]), np.repeat(np.nan, 4), np.array([0.15])))})
看起来像这样:
A B C D
0 0.537109 NaN -0.204046 NaN
1 0.744488 NaN 0.903607 NaN
2 0.640995 NaN 0.712210 NaN
3 0.212758 NaN 0.293984 NaN
4 -1.786725 0.7 0.282747 0.20
5 1.486037 NaN -0.199659 NaN
6 0.267356 NaN 0.890397 NaN
7 0.697408 NaN -0.771626 NaN
8 0.044247 NaN -1.157836 NaN
9 0.345658 0.5 1.556390 0.15
我想计算一些统计数据,比如这个数据帧切片的平均值,例如,我希望结果看起来像:
MeanA B MeanC D
0 2.1 0.7 1.3 0.20
1 1.4 0.5 5.6 0.15
换句话说,我想保留B和D列的非NA值,并计算B和D中非NA值之上/之下的值的A和C的平均值和其他值(在这种情况下,让我们在两个平均值中都包括-1.786725,类似于0.282747(
注:MeanA和MeanC中的值是由于使用了np.random.randn((.而组成的
当然,现在我的真实数据帧包含更多的列和行,所以概括一下会很好。
这应该做:
b_nans = df[~df.B.isnull()].index.values
cols_stats = ['A','C']
cols_nans = ['B','D']
df2 = pd.DataFrame(columns = [['mean_'+ col for col in cols] + cols_nans])
for col_stat, col_nan in zip(cols_stats, cols_nans):
df2[col_nan] = df[~df[col_nan].isnull()][col_nan].reset_index(drop=True)
i_prev = 0
for k,i in enumerate(b_nans):
df2.loc[k, 'mean_'+ col_stat] = df.loc[i_prev:i,col_stat].mean()
i_prev = i
print(df2)
mean_A mean_C B D
0 -0.059588 0.367446 0.7 0.20
1 0.037202 0.373243 0.5 0.15
实现这一点的一种方法是手动处理索引。让我们获取非NaN行的索引,例如通过
ind = np.array(df.dropna().index)
既然知道了索引,就可以手动执行操作了。
您可以通过以下步骤来解决问题:
-
通过以下代码找到遇到第一个非Nan值的索引:
index = df['B'].first_valid_index()
##这将返回4个 -
现在用这些索引值对df进行切片
subset_df = df.iloc[0:index+1:,]
-
取所有列的子集df的平均值
upper_half_mean = subset_df .mean(axis=0)
执行步骤2&3表示df的下面部分,然后只是concat。
这里有一个非常简单的方法。其思想是找到每列都包含一个值的行(索引((断点(。遍历这些断点并使用这些索引来获取数据帧的子片段。计算该切片中每列的平均值,这将返回该切片的单个序列。然后将这些切片(系列(连接在一起
np.random.seed(123)
# generate random data same way as in your question
# get indices of the breakpoints
idx = df[-df.isnull().any(axis=1)].index
idx = np.insert(idx, 0, 0) # idx will be [0, 4, 9]
# calculate mean across columns for each slice of the dataframe
# this creates a list of pandas series
slices = []
for i in range(len(idx)-1):
slices.append(df[idx[i]:idx[i+1]+1].mean())
# concat the separate series together as rows
output = pd.concat(slices, axis=1).T
# this is needed to get the correct values of the nan columns
output[['B', 'D']] = df[['B', 'D']].dropna().values
哪个给出:
A B C D
0 -0.378040 0.7 -0.073018 0.20
1 -0.230593 0.5 0.817437 0.15