【问题标题】:Merge object with pandas dataframe将对象与熊猫数据框合并
【发布时间】:2020-11-23 21:22:09
【问题描述】:

您会在下方看到我有一个名为 westCountries 的对象,您会在下方看到我有一个名为 countryDf 的数据框。

westCountries = {'West': ['US', 'CA', 'PR']}
# countryDF

      Country 
0        [US]
1        [PR]
2        [CA]
3        [HK]

我想知道如何在名为 Location 的新列中将 westCountries obj 包含到我的数据框中?我尝试过合并,但这并没有真正做任何事情,因为奇怪的是,我需要此列中的值作为对象中我的键的名称,如下所示。注意:这个输出只是一个例子,我知道我提供的数据和我想要的输出之间缺少相关性。

  Country Location
0      US     West
1      CA     West

我正在考虑做一些事情,例如:

  • 使用 .isin(),然后使用该数据框进行更多转换/计算以填充我的数据框,但这条路线对我来说似乎有点模糊。
  • 使用 df.loc[...] 将我的数据框与此列表中的值进行比较,然后我可以使用我选择的值创建自己的列。
  • 将我的对象转换为数据框,然后在此临时数据框中创建一个新列,然后按国家/地区合并,以便我可以将位置列包含到我的 countryDF 数据框中。

但是,我觉得可能有比我上面列出的所有这些方法更复杂的解决方案。这就是我寻求帮助的原因。

【问题讨论】:

    标签: python pandas dataframe


    【解决方案1】:
    • 使用pandas.DataFrame.explode 从列表中删除值
    • 使用list comprehension 将值与westCountries 值列表匹配并返回key
    • 例如,示例数据框列值创建为字符串,需要转换为dict 类型与ast.literal_eval
    import pandas as pd
    from ast import literal_eval  # only for setting up the test dataframe
    
    # setup the test dataframe
    data = {'Country': ["['US']", "['PR']", "['CA']", "['HK']"]}
    df = pd.DataFrame(data)
    df.Country = df.Country.apply(literal_eval)  # only for the test data
    
    westCountries = {'West': ['US', 'CA', 'PR']}
    
    # remove the values from lists, with explode
    df = df.explode('Country')
    
    # create the Loc column using apply
    df['Loc'] = df.Country.apply(lambda x: [k if x in v else None for k, v in westCountries.items()][0])
    
    # drop rows with None
    df = df.dropna()
    
    # display(df)
      Country   Loc
    0      US  West
    1      PR  West
    2      CA  West
    

    选项 2(更好):

    • 在第一个选项中,对于每一行,.apply 必须使用 [k if x in v else None for k, v in westCountries.items()] 遍历 westCountries 中的每个 key-value 对,这很慢。
    • 最好将westCountries 重塑为平面dict,以valuestate 的区域为键,使用dict comprehension
    • 使用pandas.Series.mapdict 值映射到新列中
    import pandas as pd
    from ast import literal_eval  # only for setting up the test dataframe
    
    # setup the test dataframe
    data = {'Country': ["['US']", "['PR']", "['CA']", "['HK']"]}
    df = pd.DataFrame(data)
    df.Country = df.Country.apply(literal_eval)  # only for the test data
    
    # remove the values from lists, with explode
    df = df.explode('Country')
    
    # given
    westCountries = {'West': ['US', 'CA', 'PR'], 'East': ['NY', 'NC']}
    
    # unpack westCountries where all values are keys and key are values
    mapped = {x: k for k, v in westCountries.items() for x in v}
    
    # print(mapped)
    {'US': 'West', 'CA': 'West', 'PR': 'West', 'NY': 'East', 'NC': 'East'}
    
    # map the dict to the column
    df['Loc'] = df.Country.map(mapped)
    
    # dropna
    df = df.dropna()
    

    【讨论】:

      【解决方案2】:

      您可以使用pd.melt,然后使用df.explodedf.merge 分解df

      westCountries = {'West': ['US', 'CA', 'PR']}
      west = pd.melt(pd.DataFrame(westCountries), var_name='Loc', value_name='Country')
      
      df.explode('Country').merge(west, on='Country')
        Country   Loc
      0      US  West
      1      PR  West
      2      CA  West
      

      详情

      pd.DataFrame(westCountries)
      
      #  West
      #0   US
      #1   CA
      #2   PR
      
      # Now melt the above dataframe
      pd.melt(pd.DataFrame(westCountries), var_name='Loc', value_name='Country')
      
      #    Loc Country
      #0  West      US
      #1  West      CA
      #2  West      PR
      
      # Now, merge `df` after exploding with `west` on `Country`
      df.explode('Country').merge(west, on='Country') # how = 'left' by default in merge
      
      #  Country   Loc
      #0      US  West
      #1      PR  West
      #2      CA  West
      

      编辑:

      如果你有大小不等的westCountries dict,那么试试这个

      from itertools import zip_longest
      
      westCountries = {'West': ['US', 'CA', 'PR'], 'East': ['NY', 'NC']}
      
      west = pd.DataFrame(zip_longest(*westCountries.values(),fillvalue = np.nan),
                          columns= westCountries.keys())
      west = west.melt(var_name='Loc', value_name='Country').dropna()
      
      df.explode('Country').merge(west, on='Country')
      

      以上示例:

      df
        Country
      0    [US]
      1    [PR]
      2    [CA]
      3    [HK]
      4    [NY] #--> added `NY` from `East`.
      
      westCountries = {'West': ['US', 'CA', 'PR'], 'East': ['NY', 'NC']}
      
      west = pd.DataFrame(zip_longest(*westCountries.values(),fillvalue = np.nan),
                          columns= westCountries.keys())
      west = west.melt(var_name='Loc', value_name='Country').dropna()
      df.explode('Country').merge(west, on='Country')
      
      #  Country   Loc
      #0      US  West
      #1      PR  West
      #2      CA  West
      #3      NY  East
      

      【讨论】:

        【解决方案3】:

        就运行时间而言,这可能不是最快的方法,但它确实有效

        import pandas as pd
        
        westCountries = {'West': ['US', 'CA', 'PR']}
        df = pd.DataFrame(["[US]","[PR]", "[CA]", "[HK]"], columns=["Country"])
        
        df = df.assign(Location="")
        for index, row in df.iterrows():
            if any([True for country in westCountries.get('West') if country in row['Country']]):
            row.Location='West'
        
        west_df = df[df['Location'] != ""]
        

        【讨论】:

          猜你喜欢
          • 2013-09-26
          • 1970-01-01
          • 2016-08-01
          • 1970-01-01
          • 1970-01-01
          • 2018-05-07
          • 2019-02-24
          • 2018-07-22
          • 2018-04-16
          相关资源
          最近更新 更多