8wDlpd.png
8wDFp9.png
8wDEOx.png
8wDMfH.png
8wDKte.png

将 Pandas 列表中的一列拆分为多列

Achal Utkarsh 1月前

48 0

我有一个带有一列的 Pandas DataFrame:import pandas as pddf = pd.DataFrame({\'teams\': [[\'SF\', \'NYG\'] for _ in range(7)]}) teams0 [SF, NYG]1 [SF, NYG]...

我有一个包含一列的 Pandas DataFrame:

import pandas as pd

df = pd.DataFrame({"teams": [["SF", "NYG"] for _ in range(7)]})

       teams
0  [SF, NYG]
1  [SF, NYG]
2  [SF, NYG]
3  [SF, NYG]
4  [SF, NYG]
5  [SF, NYG]
6  [SF, NYG]

如何将这一列列表分成两列?

期望结果:

  team1 team2
0    SF   NYG
1    SF   NYG
2    SF   NYG
3    SF   NYG
4    SF   NYG
5    SF   NYG
6    SF   NYG
帖子版权声明 1、本帖标题:将 Pandas 列表中的一列拆分为多列
    本站网址:http://xjnalaquan.com/
2、本网站的资源部分来源于网络,如有侵权,请联系站长进行删除处理。
3、会员发帖仅代表会员个人观点,并不代表本站赞同其观点和对其真实性负责。
4、本站一律禁止以任何方式发布或转载任何违法的相关信息,访客发现请向站长举报
5、站长邮箱:yeweds@126.com 除非注明,本帖由Achal Utkarsh在本站《pandas》版块原创发布, 转载请注明出处!
最新回复 (0)
  • 您可以使用 DataFrame 构造函数 lists 创建的 to_list :

    import pandas as pd
    
    d1 = {'teams': [['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG'],
                    ['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG']]}
    df2 = pd.DataFrame(d1)
    print (df2)
           teams
    0  [SF, NYG]
    1  [SF, NYG]
    2  [SF, NYG]
    3  [SF, NYG]
    4  [SF, NYG]
    5  [SF, NYG]
    6  [SF, NYG]
    

    df2[['team1','team2']] = pd.DataFrame(df2.teams.tolist(), index= df2.index)
    print (df2)
           teams team1 team2
    0  [SF, NYG]    SF   NYG
    1  [SF, NYG]    SF   NYG
    2  [SF, NYG]    SF   NYG
    3  [SF, NYG]    SF   NYG
    4  [SF, NYG]    SF   NYG
    5  [SF, NYG]    SF   NYG
    6  [SF, NYG]    SF   NYG
    

    对于新的 DataFrame

    df3 = pd.DataFrame(df2['teams'].to_list(), columns=['team1','team2'])
    print (df3)
      team1 team2
    0    SF   NYG
    1    SF   NYG
    2    SF   NYG
    3    SF   NYG
    4    SF   NYG
    5    SF   NYG
    6    SF   NYG
    

    解决方案 apply(pd.Series) 非常慢:

    #7k rows
    df2 = pd.concat([df2]*1000).reset_index(drop=True)
    
    In [121]: %timeit df2['teams'].apply(pd.Series)
    1.79 s ± 52.5 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    In [122]: %timeit pd.DataFrame(df2['teams'].to_list(), columns=['team1','team2'])
    1.63 ms ± 54.3 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
    
  • List 方法会重置索引。如果要保留索引,请在使用 df1.index = d2.index 构造 df2 后复制索引。

  • 怎么样:df1.apply(lambda x:x[\'teams\'],result_type=\'expand\',axis=1)

  • 似乎只有当所有列表的长度相同时,'tolist' 方法才有效。

  • 更简单的解决方案:

    pd.DataFrame(df2["teams"].to_list(), columns=['team1', 'team2'])
    

    产量,

      team1 team2
    -------------
    0    SF   NYG
    1    SF   NYG
    2    SF   NYG
    3    SF   NYG
    4    SF   NYG
    5    SF   NYG
    6    SF   NYG
    7    SF   NYG
    

    如果您想要拆分一列分隔字符串而不是列表,您可以类似地这样做:

    pd.DataFrame(df["teams"].str.split('<delim>', expand=True).values,
                 columns=['team1', 'team2'])
    
  • jxh 1月前 0 只看Ta
    引用 7

    如果您想要拆分一列分隔字符串而不是列表,您可以类似地执行以下操作:df[\'teams\'].str.split('', expand=True) 已经返回了一个 DataFrame,因此重命名列可能会更简单。

  • 感谢@AMC 帮我完成了这个工作,但是由于我的 UUID 的 \'list\' 实际上是一个假装是列表的 str,所以首先我必须应用 lambda 来删除方括号。

  • 此解决方案保留了 DataFrame 的索引 df2 ,与使用以下方法的任何解决方案不同 tolist()

    df3 = df2.teams.apply(pd.Series)
    df3.columns = ['team1', 'team2']
    

    结果如下:

      team1 team2
    0    SF   NYG
    1    SF   NYG
    2    SF   NYG
    3    SF   NYG
    4    SF   NYG
    5    SF   NYG
    6    SF   NYG
    
  • .apply(pd.Series) 很容易记住和输入。不幸的是,正如其他答案所述,对于大量观察,它也非常慢。如果要保存的索引很容易访问,则使用 DataFrame 构造函数方法进行保存就像将索引参数传递给构造函数一样简单,如其他答案所示。在方法链的中间,一种解决方法是使用赋值表达式(Python 3.8+)存储中间 Series 或 DataFrame,然后从那里访问索引。

  • 与建议的解决方案相比,似乎有一种语法上更简单的方法,因此更容易记住。我假设该列在数据框 df 中称为“meta”:

    df2 = pd.DataFrame(df['meta'].str.split().values.tolist())
    
  • 这个答案很有帮助,并且可以与该技术的视觉演示相结合:youtube.com/watch?v=vPKwm1XZjp8

  • 我想推荐一种更高效、更 Pythonic 的方式。

    首先定义 DataFrame 为原始帖子:

    df = pd.DataFrame({"teams": [["SF", "NYG"] for _ in range(7)]})
    

    我的解决方案:

    %%timeit
    df['team1'], df['team2'] = zip(*list(df['teams'].values))
    >> 761 µs ± 8.35 µs per loop
    

    相比之下,获得最多支持的方案是:

    %%timeit
    df[['team1','team2']] = pd.DataFrame(df.teams.tolist(), index=df.index)
    df = pd.DataFrame(df['teams'].to_list(), columns=['team1','team2'])
    >> 1.31 ms ± 11.2 µs per loop
    

    我的解决方案节省了 40% 的时间,而且代码更短。你唯一需要记住的是如何使用 zip(*list) .

  • 这个 df['team1'], df['team2'] = zip(*list(df['teams'].values)) 应该是可接受的答案。简单、易读、惯用。

  • 列表推导

    使用列表推导的简单实现(我最喜欢的)

    df = pd.DataFrame([pd.Series(x) for x in df.teams])
    df.columns = ['team_{}'.format(x+1) for x in df.columns]
    

    输出时序:

    CPU times: user 0 ns, sys: 0 ns, total: 0 ns
    Wall time: 2.71 ms
    
    

    输出:

    team_1    team_2
    0    SF    NYG
    1    SF    NYG
    2    SF    NYG
    3    SF    NYG
    4    SF    NYG
    5    SF    NYG
    6    SF    NYG
    
  • 以前的解决方案对我不起作用,因为我有 nan 观察结果 dataframe 。 在我的例子中, df2[['team1','team2']] = pd.DataFrame(df2.teams.values.tolist(), index= df2.index) 结果是:

    object of type 'float' has no len()
    

    我使用列表推导式来解决这个问题。以下是可复制的示例:

    import pandas as pd
    import numpy as np
    d1 = {'teams': [['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG'],
                ['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG']]}
    df2 = pd.DataFrame(d1)
    df2.loc[2,'teams'] = np.nan
    df2.loc[4,'teams'] = np.nan
    df2
    

    输出:

            teams
    0   [SF, NYG]
    1   [SF, NYG]
    2   NaN
    3   [SF, NYG]
    4   NaN
    5   [SF, NYG]
    6   [SF, NYG]
    
    df2['team1']=np.nan
    df2['team2']=np.nan
    

    使用列表推导式解决,

    for i in [0,1]:
        df2['team{}'.format(str(i+1))]=[k[i] if isinstance(k,list) else k for k in df2['teams']]
    
    df2
    

    产量:

        teams   team1   team2
    0   [SF, NYG]   SF  NYG
    1   [SF, NYG]   SF  NYG
    2   NaN        NaN  NaN
    3   [SF, NYG]   SF  NYG
    4   NaN        NaN  NaN
    5   [SF, NYG]   SF  NYG
    6   [SF, NYG]   SF  NYG
    
  • pb94 1月前 0 只看Ta
    引用 17

    这是使用 df.transform and df.set_index :

    >>> from operator import itemgetter
    >>> df['teams'].transform({'item1': itemgetter(0), 'item2': itemgetter(1)})
    
      team1 team2
    0    SF   NYG
    1    SF   NYG
    2    SF   NYG
    3    SF   NYG
    4    SF   NYG
    5    SF   NYG
    6    SF   NYG
    

    当然可以概括为:

    >>> indices = range(len(df['teams'][0]))
    
    >>> df['teams'].transform({f'team{i+1}': itemgetter(i) for i in indices})
    
      team1 team2
    0    SF   NYG
    1    SF   NYG
    2    SF   NYG
    3    SF   NYG
    4    SF   NYG
    5    SF   NYG
    6    SF   NYG
    

    这种方法还有提取所需索引的额外好处:

    >>> df
                     teams
    0  [SF, NYG, XYZ, ABC]
    1  [SF, NYG, XYZ, ABC]
    2  [SF, NYG, XYZ, ABC]
    3  [SF, NYG, XYZ, ABC]
    4  [SF, NYG, XYZ, ABC]
    5  [SF, NYG, XYZ, ABC]
    6  [SF, NYG, XYZ, ABC]
    
    >>> indices = [0, 2]
    >>> df['teams'].transform({f'team{i+1}': itemgetter(i) for i in indices})
    
      team1 team3
    0    SF   XYZ
    1    SF   XYZ
    2    SF   XYZ
    3    SF   XYZ
    4    SF   XYZ
    5    SF   XYZ
    6    SF   XYZ
    
  • 根据前面的答案,这里是另一个解决方案,它返回与 df2.teams.apply(pd.Series) 相同的结果,但运行时间更快:

    pd.DataFrame([{x: y for x, y in enumerate(item)} for item in df2['teams'].values.tolist()], index=df2.index)
    

    时间安排:

    In [1]:
    import pandas as pd
    d1 = {'teams': [['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG'],
                    ['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG'],['SF', 'NYG']]}
    df2 = pd.DataFrame(d1)
    df2 = pd.concat([df2]*1000).reset_index(drop=True)
    
    In [2]: %timeit df2['teams'].apply(pd.Series)
    
    8.27 s ± 2.73 s per loop (mean ± std. dev. of 7 runs, 1 loop each)
    
    In [3]: %timeit pd.DataFrame([{x: y for x, y in enumerate(item)} for item in df2['teams'].values.tolist()], index=df2.index)
    
    35.4 ms ± 5.22 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)
    
  • 引用 19

    如果有人来这里寻找现成的函数,我写了一个。

    • 没有指定, columns 它会找到所有带有列表的列并展开它们
    • 添加的列命名为 column_name_0 , column_name_1 ,等等;
    • 列的顺序保留在最终的数据框中;
    • 如果是 strict=True ,它会检查给定列中的列表是否大小相等。

    欢迎提出改进和意见。

    def unfold_columns(df, columns=[], strict=False):
        assert isinstance(columns, list), "Columns should be a list of column names"
        if len(columns) == 0:
            columns = [
                column for column in df.columns 
                if df.applymap(lambda x: isinstance(x, list)).all()[column]
            ]
        else:
            assert(all([(column in df.columns) for column in columns])), \
                "Not all given columns are found in df"
        columns_order = df.columns
        for column_name in columns:
            if df[column_name].apply(lambda x: isinstance(x, list)).all():
                if strict:
                    assert len(set(df[column_name].apply(lambda x: len(x)))) == 1, \
                        f"Lists in df['{column_name}'] are not of equal length"
                unfolded = pd.DataFrame(df[column_name].tolist())
                unfolded.columns = [f'{column_name}_{x}' for x in unfolded.columns]
                columns_order = [
                    *columns_order[:list(columns_order).index(column_name)], 
                    *unfolded.columns, 
                    *columns_order[list(columns_order).index(column_name)+1:]
                ]
                df = df.join(unfolded).drop([column_name], axis=1)
        return df[columns_order]
    
  • 要将 附加 到现有的 DataFrame:

    df[['team1', 'team2']] = df["teams"].to_list()
    
返回
作者最近主题: