【问题标题】:How to create columns based on combinations of values between 2 sets of columns?如何根据两组列之间的值组合创建列?
【发布时间】:2018-12-09 16:54:45
【问题描述】:

我有一个带有逗号分隔值的数据框,我使用 pd.concat 将其拆分出来。

原始df:

org    country         type
Orange   USA, GBR, AUS   OWF, PMR, KIQ
Red      AUS, RUS, NZL   DOG, MOP, LOF

拆分列会给我一个 df,我们称之为 df_wide,

org        country_1    country_2   country_3   type_1   type_2   type_3
Orange        USA          GBR         AUS         OWF      PMR      KIQ
Watermelon    AUS          RUS         NZL         ODG      MOP      LOF

从上面的数据框中,我需要以长格式获取单个国家和单个类型的所有可能组合:

org     country    type
Orange  USA        OWF
Orange  USA        PMR
Orange  USA        KIQ
Orange  GBR        OWF
Orange  GBR        PMR
Orange  GBR        KIQ

..等等

这就是我卡住的地方。我错误地认为我可以使用 pd.wide_to_long 转换数据框,但我认为我的答案围绕使用 itertools。我已经搜索了与此问题相关的论坛,但我仍然没有完全弄清楚。寻找任何建议!原始 df 列中的逗号分隔值也可能是几十个值,因此我不知道我的宽 df 将有多少列宽。

【问题讨论】:

    标签: python pandas dataframe itertools


    【解决方案1】:

    这是使用itertools.product 的一种解决方案。它不需要您创建的中间数据框。

    from itertools import chain, product
    
    df = pd.DataFrame({'org': ['Orange', 'Red'],
                       'country': ['USA, GBR, AUS', 'AUS, RUS, NZL'],
                       'type': ['OWF, PMR, KIQ', 'DOG, MOP, LOF']})
    
    split1 = df['country'].str.split(', ')
    split2 = df['type'].str.split(', ')
    
    lens = split1.map(len) * split2.map(len)
    
    c_list, t_list = zip(*chain.from_iterable(map(product, split1, split2)))
    
    res = pd.DataFrame({'org': np.repeat(df['org'], lens),
                        'country': c_list,
                        'type': t_list})
    

    说明

    魔法发生在这行:

    c_list, t_list = zip(*chain.from_iterable(map(product, split1, split2)))
    

    由内而外的工作:

    • 计算split1 / split2 中每对项目的笛卡尔积。
    • 将它们链接在一起,形成一个非嵌套的可迭代结果。
    • 解压并压缩到国家和类型。

    结果

    print(res)
    
          org country type
    0  Orange     USA  OWF
    0  Orange     USA  PMR
    0  Orange     USA  KIQ
    0  Orange     GBR  OWF
    0  Orange     GBR  PMR
    0  Orange     GBR  KIQ
    0  Orange     AUS  OWF
    0  Orange     AUS  PMR
    0  Orange     AUS  KIQ
    1     Red     AUS  DOG
    1     Red     AUS  MOP
    1     Red     AUS  LOF
    1     Red     RUS  DOG
    1     Red     RUS  MOP
    1     Red     RUS  LOF
    1     Red     NZL  DOG
    1     Red     NZL  MOP
    1     Red     NZL  LOF
    

    【讨论】:

      【解决方案2】:

      只需借用 jpp 的设置,使用pd.MultiIndex.from_product

      df['country'] = df['country'].str.split(', ')
      df['type'] = df['type'].str.split(', ')
      s=[pd.MultiIndex.from_product(x).tolist() for x in list(zip(df['country'],df['type']))]
      
      df=pd.DataFrame({'org':df.org.repeat(list(map(len,s)))}).reset_index(drop=True)
      
      df[['country','type']]=pd.DataFrame(sum(s,[]))
      df
             org country type
      0   Orange     USA  OWF
      1   Orange     USA  PMR
      2   Orange     USA  KIQ
      3   Orange     GBR  OWF
      4   Orange     GBR  PMR
      5   Orange     GBR  KIQ
      6   Orange     AUS  OWF
      7   Orange     AUS  PMR
      8   Orange     AUS  KIQ
      9      Red     AUS  DOG
      10     Red     AUS  MOP
      11     Red     AUS  LOF
      12     Red     RUS  DOG
      13     Red     RUS  MOP
      14     Red     RUS  LOF
      15     Red     NZL  DOG
      16     Red     NZL  MOP
      17     Red     NZL  LOF
      

      【讨论】:

        【解决方案3】:

        我从设置 df 开始:

        import pandas
        records = [
            {
                "org": "Orange",
                "country_1": "USA",
                "country_2": "GBR",
                "country_3": "AUS",
                "type_1": "OWF",
                "type_2": "PMR",
                "type_3": "KIQ"
            },
            {
                "org": "Watermelon",
                "country_1": "AUS",
                "country_2": "RUS",
                "country_3": "NZL",
                "type_1": "ODG",
                "type_2": "MOP",
                "type_3": "LOF"
            }
        ]
        
        df = pandas.DataFrame(records)
        

        首先,您可以使用pandas.DataFrame 的.filter 方法通过正则表达式选择列(如here 所示):

        >>> df_countries = df.filter(regex=("country_.*"))
          country_1 country_2 country_3
        0       USA       GBR       AUS
        1       AUS       RUS       NZL
        
        >>> df_types = df.filter(regex=("type_.*"))
          type_1 type_2 type_3
        0    OWF    PMR    KIQ
        1    ODG    MOP    LOF
        

        然后你可以得到所有独特的国家和类型:

        >>> countries_all = df_countries.values.flatten()
        array(['USA', 'GBR', 'AUS', 'AUS', 'RUS', 'NZL'], dtype=object)
        >>> types_all = df_types.values.flatten()
        array(['OWF', 'PMR', 'KIQ', 'ODG', 'MOP', 'LOF'], dtype=object)
        

        然后将它们组合起来就是使用来自itertools 的笛卡尔积:

        >>> pandas.DataFrame(list(itertools.product(*[list(countries_all), list(types_all)])))
              0    1
        0   USA  OWF
        1   USA  PMR
        2   USA  KIQ
        3   USA  ODG
        4   USA  MOP
        5   USA  LOF
        6   GBR  OWF
        7   GBR  PMR
        8   GBR  KIQ
        9   GBR  ODG
        10  GBR  MOP
        11  GBR  LOF
        12  AUS  OWF
        13  AUS  PMR
        14  AUS  KIQ
        15  AUS  ODG
        16  AUS  MOP
        17  AUS  LOF
        18  AUS  OWF
        19  AUS  PMR
        20  AUS  KIQ
        21  AUS  ODG
        22  AUS  MOP
        23  AUS  LOF
        24  RUS  OWF
        25  RUS  PMR
        26  RUS  KIQ
        27  RUS  ODG
        28  RUS  MOP
        29  RUS  LOF
        30  NZL  OWF
        31  NZL  PMR
        32  NZL  KIQ
        33  NZL  ODG
        34  NZL  MOP
        35  NZL  LOF
        

        现在我知道您可能希望按照 org 执行此操作,在这种情况下,我会在执行过滤器之前对数据帧进行子集化:

        orgs = pandas.unique(df["org"])
        for org in orgs:
            df_org = df[df["org"] == org]
            df_countries = df_org.filter(regex=("country_.*"))
            df_types = df_org.filter(regex=("type_.*"))
            # do rest of the process here and concatenate in the end through `pandas.concat`
        

        希望对你有帮助

        【讨论】:

          猜你喜欢
          • 2017-06-24
          • 1970-01-01
          • 2021-04-30
          • 2019-12-01
          • 2023-04-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-09-01
          相关资源
          最近更新 更多