首页 > 解决方案 > 如何将行与 DataFrame 中的值组合合并

问题描述

我有一个 DataFrame (df1),如下所示

    Hair  Feathers  Legs  Type  Count
 R1  1       NaN     0     1      1
 R2  1        0      Nan   1      32
 R3  1        0      2     1      4
 R4  1       Nan     4     1      27

我想根据每列中值的不同组合来合并行,并且还想为每个合并的行添加计数值。结果数据帧(df2)将如下所示:

    Hair  Feathers  Legs  Type  Count
 R1   1      0        0     1     33
 R2   1      0        2     1     36
 R3   1      0        4     1     59

合并的执行方式是任何Nan值都将与 0 或 1 合并。在 df2 中,通过将NanFeathers (df1,R1) 的值与 Feathers (df1,R2) 的 0 值合并来计算 R1。同样,Legs (df1,R1) 中的 0 值与 Legs (df1,R2) 值合并Nan。然后将 R1 (1) 和 R2(32) 的计数相加。以相同的方式合并 R2 和 R3,因为 R2 (df1) 中的 Feathers 值与 R3 (df1) 相似,而 Legs 值Nan与 R3 (df1) 中的 2 以及 R2 (32) 和 R3 (4) 的计数合并被添加。

我希望解释是有道理的。任何帮助将不胜感激

标签: pythonpandasdataframecombinations

解决方案


一种可能的方法是复制包含列的每一行NaN并用列的值填充它们。

首先,我们需要获取每列可能的非空唯一值:

unique_values = df.iloc[:, :-1].apply(
       lambda x: x.dropna().unique().tolist(), axis=0).to_dict()   
> unique_values
{'Hair': [1.0], 'Feathers': [0.0], 'Legs': [0.0, 2.0, 4.0], 'Type': [1.0]}

然后遍历数据框的每一行,并用每NaN列的可能值替换每一行。我们可以使用pandas.DataFrame.iterrows

mask = df.iloc[:, :-1].isnull().any(axis=1)

# Keep the rows that do not contain `Nan`
# and then added modified rows

list_of_df = [r for i, r in df[~mask].iterrows()]

for row_index, row in df[mask].iterrows(): 

    for c in row[row.isnull()].index: 

        # For each column of the row, replace 
        # Nan by possible values for the column

        for v in unique_values[c]: 

            list_of_df.append(row.copy().fillna({c:v})) 

df_res = pd.concat(list_of_df, axis=1, ignore_index=True).T

结果是一个数据框,其中所有的NaN列都填充了可能的值:

> df_res

   Hair  Feathers  Legs  Type  Count
0   1.0       0.0   2.0   1.0    4.0
1   1.0       0.0   0.0   1.0    1.0
2   1.0       0.0   0.0   1.0   32.0
3   1.0       0.0   2.0   1.0   32.0
4   1.0       0.0   4.0   1.0   32.0
5   1.0       0.0   4.0   1.0   27.0

Count通过可能的组合获得分组的最终结果,['Hair', 'Feathers', 'Legs', 'Type']我们只需要这样做:

> df_res.groupby(['Hair', 'Feathers', 'Legs', 'Type']).sum().reset_index()  

   Hair  Feathers  Legs  Type  Count
0   1.0       0.0   0.0   1.0   33.0
1   1.0       0.0   2.0   1.0   36.0
2   1.0       0.0   4.0   1.0   59.0

希望它服务

更新

如果行中的一个或多个元素缺失,该过程会同时查找缺失值的所有可能组合。让我们添加一个缺少两个元素的新行:

> df

   Hair  Feathers  Legs  Type  Count
0   1.0       NaN   0.0   1.0    1.0
1   1.0       0.0   NaN   1.0   32.0
2   1.0       0.0   2.0   1.0    4.0
3   1.0       NaN   4.0   1.0   27.0
4   1.0       NaN   NaN   1.0   32.0

我们将以类似的方式进行,但替换组合将使用itertools.product获得:

 import itertools 

 unique_values = df.iloc[:, :-1].apply(
       lambda x: x.dropna().unique().tolist(), axis=0).to_dict()

 mask = df.iloc[:, :-1].isnull().any(axis=1) 

 list_of_df = [r for i, r in df[~mask].iterrows()] 

 for row_index, row in df[mask].iterrows():  

     cols = row[row.isnull()].index.tolist() 

     for p in itertools.product(*[unique_values[c] for c in cols]): 

         list_of_df.append(row.copy().fillna({c:v for c, v in zip(cols, p)}))

 df_res = pd.concat(list_of_df, axis=1, ignore_index=True).T       


> df_res.sort_values(['Hair', 'Feathers', 'Legs', 'Type']).reset_index(drop=True)

Hair  Feathers  Legs  Type  Count
1   1.0       0.0   0.0   1.0    1.0
2   1.0       0.0   0.0   1.0   32.0
6   1.0       0.0   0.0   1.0   32.0
0   1.0       0.0   2.0   1.0    4.0
3   1.0       0.0   2.0   1.0   32.0
7   1.0       0.0   2.0   1.0   32.0
4   1.0       0.0   4.0   1.0   32.0
5   1.0       0.0   4.0   1.0   27.0
8   1.0       0.0   4.0   1.0   32.0

> df_res.groupby(['Hair', 'Feathers', 'Legs', 'Type']).sum().reset_index()

   Hair  Feathers  Legs  Type  Count
0   1.0       0.0   0.0   1.0   65.0
1   1.0       0.0   2.0   1.0   68.0
2   1.0       0.0   4.0   1.0   91.0

推荐阅读