如何将可变长度列表的 Pandas DataFrame 列(或系列)转换为固定宽度的 DataFrame [重复]

Posted

技术标签:

【中文标题】如何将可变长度列表的 Pandas DataFrame 列(或系列)转换为固定宽度的 DataFrame [重复]【英文标题】:How to convert a Pandas DataFrame column (or Series) of variable-length lists to a DataFrame of fixed width [duplicate] 【发布时间】:2021-02-19 19:30:40 【问题描述】:

我想将具有不同长度列表的 DataFrame 列(或 Series)转换为具有固定列数的 DataFrame。

DataFrame 将具有与最长列表一样多的列,而其他列表较短的值可以是 NaN 或任何值。

当数据以字符串形式出现时,str 模块允许这样做,str.split 中的选项 expand。但我无法找到可变长度列表的等价物。

在我的示例中,列表中的类型是 int,但我们的想法是可以使用任何类型。这可以防止简单地将 Series 转换为 str 并应用提到的 expand 属性。

下面我展示了使用 str.split 函数运行带有列表的示例的代码,以及要转换的系列的最小示例。

我找到了一个使用 apply 的解决方案,如示例中所示,但速度极慢以至于没有用处。

import numpy as np
import pandas as pd

# Example with a list as a string
A = pd.DataFrame('lists': [
                    '[]',
                    '[360,460,160]',
                    '[360,1,2,3,4,5,6]',
                    '[10,20,30]',
                    '[100,100,100,100]',
                    ],
                  'other': [1,2,3,4,5]
                 )
print(A['lists'].astype(str).str.strip('[]').str.split(',', expand=True))

# Example with actual lists
B = pd.DataFrame('lists': [
                    [],
                    [360,460,160],
                    [360,1,2,3,4,5,6],
                    [10,20,30],
                    [100,100,100,100],
                ],
                  'other': [1,2,3,4,5]
                 )

# Create and pre-fill expected columns
max_len = max(B['lists'].str.len())
for idx in range(max_len):
    B[f'lists_idx'] = np.nan

# Use .apply to fill the columns
def expand_int_list(row, col, df):
    for idx, item in enumerate(row[col]):
        df.loc[row.name, f'col_idx'] = item
        
B.apply(lambda row: expand_int_list(row, 'lists', B), axis=1)
print(B)

输出:

     0     1     2     3     4     5     6
0       None  None  None  None  None  None
1  360   460   160  None  None  None  None
2  360     1     2     3     4     5     6
3   10    20    30  None  None  None  None
4  100   100   100   100  None  None  None
                     lists  other  lists_0  lists_1  lists_2  lists_3  \
0                       []      1      NaN      NaN      NaN      NaN   
1          [360, 460, 160]      2    360.0    460.0    160.0      NaN   
2  [360, 1, 2, 3, 4, 5, 6]      3    360.0      1.0      2.0      3.0   
3             [10, 20, 30]      4     10.0     20.0     30.0      NaN   
4     [100, 100, 100, 100]      5    100.0    100.0    100.0    100.0   

   lists_4  lists_5  lists_6  
0      NaN      NaN      NaN  
1      NaN      NaN      NaN  
2      4.0      5.0      6.0  
3      NaN      NaN      NaN  
4      NaN      NaN      NaN  

编辑和最终解决方案: 使其他问题中找到的方法失败的重要信息是,在我的数据中,有时我有 None 而不是列表。

在这种情况下,使用tolist() 将再次生成一系列列表,Pandas 不允许使用B.loc[B[col].isna(), col] = [] 将这些单元格设为空列表。

我找到的解决方案是只在非None的行中使用tolist(),而concat使用原始索引:

# Example with actual lists
B = pd.DataFrame('lists': [
                    [],
                    [360,460,160],
                    None,
                    [10,20,30],
                    [100,100,100,100],
                ],
                  'other': [1,2,3,4,5]
                 )

col = 'lists'
# I need to keep the index for the concat afterwards.
extended = pd.DataFrame(B.loc[~B[col].isna(), col].tolist(),
                        index=B.loc[~B[col].isna()].index)
extended = extended.add_prefix(f'col_')
B = pd.concat([B, extended], axis=1)

print(B)

输出:

                  lists  other  lists_0  lists_1  lists_2  lists_3
0                    []      1      NaN      NaN      NaN      NaN
1       [360, 460, 160]      2    360.0    460.0    160.0      NaN
2                  None      3      NaN      NaN      NaN      NaN
3          [10, 20, 30]      4     10.0     20.0     30.0      NaN
4  [100, 100, 100, 100]      5    100.0    100.0    100.0    100.0

【问题讨论】:

这能回答你的问题吗? How to create a Pandas DataFrame from a list of lists with different lengths? 感谢@MayankPorwal 的建议,由于长度可变,我认为它不适用于我的情况,但原因是有时使用 None 而不是列表。我会更新问题。 【参考方案1】:

如果将嵌套列表转换为列表并传递给DataFrame 构造函数,缺失值会像最长列表一样添加,然后DataFrame.add_prefix 并由DataFrame.join 附加到原始:

df = B.join(pd.DataFrame(B['lists'].tolist()).add_prefix('lists_'))
print (df)
                     lists  other  lists_0  lists_1  lists_2  lists_3  \
0                       []      1      NaN      NaN      NaN      NaN   
1          [360, 460, 160]      2    360.0    460.0    160.0      NaN   
2  [360, 1, 2, 3, 4, 5, 6]      3    360.0      1.0      2.0      3.0   
3             [10, 20, 30]      4     10.0     20.0     30.0      NaN   
4     [100, 100, 100, 100]      5    100.0    100.0    100.0    100.0   

   lists_4  lists_5  lists_6  
0      NaN      NaN      NaN  
1      NaN      NaN      NaN  
2      4.0      5.0      6.0  
3      NaN      NaN      NaN  
4      NaN      NaN      NaN  

【讨论】:

感谢@jezrael 的回复。我之前尝试过 .tolist() 并认为由于可变长度列表而无法正常工作,但有时我有 None 而不是列表。我将更新问题并添加找到的解决方案,从您的回复开始。

以上是关于如何将可变长度列表的 Pandas DataFrame 列(或系列)转换为固定宽度的 DataFrame [重复]的主要内容,如果未能解决你的问题,请参考以下文章

肝了3天,整理了90个Pandas案例!

肝了3天,整理了90个Pandas案例!

Pandas 将不同长度的列表分解成行

如何使用只有一个参考参数的可变长度参数列表?

Java 我在学反射的时候,遇到可变长度参数列表,具体的成员方法就是?

如何将 2 个列表的列表转换为 pandas 中的 2 列 df