【问题标题】:Pandas - Create Separate Columns in DataFrame Based on a Specific Column's ValuesPandas - 根据特定列的值在 DataFrame 中创建单独的列
【发布时间】:2018-09-03 19:03:35
【问题描述】:

假设我有一个简单的 Pandas DataFrame,其中一列包含国家名称,另一列包含一些值。例如:

# Import Python Libraries
import numpy as np
import pandas as pd

# Create Sample DataFrame
df = pd.DataFrame(data={'Country': ['United States','United States','United States','United States', \
                     'United States','United States','United States','United States', \
                     'United States','United States','United States','United States', \
                     'Canada','Canada','Canada','Canada','Canada','Canada','Mexico', \
                     'Mexico','Mexico','Mexico','England','England','England','England', \
                     'England','England','England','England','England','England','England', \
                     'England','England','England','France','France','France','Spain','Germany', \
                     'Germany','Germany','Germany','Germany','Germany','Germany','Germany', \
                     'Germany','Germany'], 'Value': np.random.randint(1000, size=50)})

生成:

print(df.head())

Index     Country     Value
  0    United States   943
  1    United States   567
  2    United States   534
  3    United States   700
  4    United States   470

我的问题是,在 Python 中,将这个 DataFrame 转换为每个国家/地区都有自己的列并且该国家/地区的所有值都列在该列中的最简单方法是什么?换句话说,我如何轻松创建一个 DataFrame,其中列数是“Country”列中国家/地区的唯一计数,并且每列的长度将根据相应国家/地区出现在原始 DataFrame 中的次数而有所不同?

这是提供解决方案的示例代码:

# Store Unique Country Names in Variable
columns = df['Country'].unique()

# Create Individual Country DataFrames
df_0 = df[df['Country'] == columns[0]]['Value'].values.tolist()
df_1 = df[df['Country'] == columns[1]]['Value'].values.tolist()
df_2 = df[df['Country'] == columns[2]]['Value'].values.tolist()
df_3 = df[df['Country'] == columns[3]]['Value'].values.tolist()
df_4 = df[df['Country'] == columns[4]]['Value'].values.tolist()
df_5 = df[df['Country'] == columns[5]]['Value'].values.tolist()
df_6 = df[df['Country'] == columns[6]]['Value'].values.tolist()

# Create Desired Output DataFrame
data_dict = {columns[0]: df_0, columns[1]: df_1, columns[2]: df_2, columns[3]: df_3, columns[4]: df_4, columns[5]: df_5, columns[6]: df_6}
new_df = pd.DataFrame({k:pd.Series(v[:len(df)]) for k,v in data_dict.items()})

生成:

print(new_df)

    United States   Canada  Mexico  England France  Spain   Germany
0   838.0           135.0   496.0   568.0   71.0    588.0   811.0
1   57.0            118.0   268.0   716.0   422.0   NaN     107.0
2   953.0           396.0   850.0   860.0   707.0   NaN     318.0
3   251.0           294.0   815.0   888.0   NaN     NaN     633.0
4   127.0           466.0   NaN     869.0   NaN     NaN     910.0
5   892.0           824.0   NaN     776.0   NaN     NaN     472.0
6   11.0            NaN     NaN     508.0   NaN     NaN     466.0
7   563.0           NaN     NaN     299.0   NaN     NaN     200.0
8   864.0           NaN     NaN     568.0   NaN     NaN     637.0
9   810.0           NaN     NaN     78.0    NaN     NaN     392.0
10  268.0           NaN     NaN     106.0   NaN     NaN     NaN
11  389.0           NaN     NaN     153.0   NaN     NaN     NaN
12  NaN             NaN     NaN     217.0   NaN     NaN     NaN
13  NaN             NaN     NaN     941.0   NaN     NaN     NaN

虽然上述代码有效,但对于较大的数据集显然不是一个可行的解决方案。从原始 DataFrame 生成此结果的最有效方法是什么?

谢谢!

【问题讨论】:

    标签: python python-3.x pandas dataframe matplotlib


    【解决方案1】:

    可能不是目前最高效的解决方案,但它会让一切都变得合理。

    df1 = df.groupby('Country').Value.agg(list).apply(pd.Series).T
    df1.columns.name=None
    

    输出:df1

        Canada  England  France  Germany  Mexico  Spain  United States
    0    653.0    187.0   396.0    491.0   251.0  433.0          919.0
    1    215.0    301.0    25.0    107.0   755.0    NaN          435.0
    2    709.0    581.0   858.0    691.0   158.0    NaN          166.0
    3    626.0    706.0     NaN    572.0   767.0    NaN          352.0
    4    516.0    999.0     NaN    393.0     NaN    NaN          906.0
    5    847.0    688.0     NaN    780.0     NaN    NaN          489.0
    6      NaN    722.0     NaN     19.0     NaN    NaN          322.0
    7      NaN    728.0     NaN    166.0     NaN    NaN          753.0
    8      NaN    765.0     NaN    299.0     NaN    NaN          155.0
    9      NaN    956.0     NaN    449.0     NaN    NaN          438.0
    10     NaN     41.0     NaN      NaN     NaN    NaN          588.0
    11     NaN     43.0     NaN      NaN     NaN    NaN          796.0
    12     NaN    485.0     NaN      NaN     NaN    NaN            NaN
    13     NaN    218.0     NaN      NaN     NaN    NaN            NaN
    

    另一种选择是使用Coldspeed's justify function 和 Yuca 的枢轴输出:

    import numpy as np
    
    df2 = df.pivot(index=None, columns='Country', values='Value')
    df2 = pd.DataFrame(
              justify(df2.values, invalid_val=np.NaN, axis=0, side='up'), 
              columns=df2.columns
              ).dropna(0, 'all')
    df2.columns.name=None
    

    输出:df2

       Canada England France Germany Mexico Spain United States
    0     653     187    396     491    251   433           919
    1     215     301     25     107    755   NaN           435
    2     709     581    858     691    158   NaN           166
    3     626     706    NaN     572    767   NaN           352
    4     516     999    NaN     393    NaN   NaN           906
    5     847     688    NaN     780    NaN   NaN           489
    6     NaN     722    NaN      19    NaN   NaN           322
    7     NaN     728    NaN     166    NaN   NaN           753
    8     NaN     765    NaN     299    NaN   NaN           155
    9     NaN     956    NaN     449    NaN   NaN           438
    10    NaN      41    NaN     NaN    NaN   NaN           588
    11    NaN      43    NaN     NaN    NaN   NaN           796
    12    NaN     485    NaN     NaN    NaN   NaN           NaN
    13    NaN     218    NaN     NaN    NaN   NaN           NaN
    

    【讨论】:

    • 看起来我很困惑
    • @Alollz 我收到一个错误,您的第一个解决方案“类型”对象不可迭代?
    • 鉴于您的输入,这不应该发生。也许分解代码以准确查看哪个部分破坏了您的真实数据。 df1 = df.groupby('Country').Value.agg(list) 然后应用系列,然后转置。
    【解决方案2】:

    groupbycumcountunstackT 一起使用:

    df.set_index(['Country',df.groupby('Country').cumcount()])['Value'].unstack().T
    

    输出:

    Country  Canada  England  France  Germany  Mexico  Spain  United States
    0         535.0    666.0   545.0    522.0   581.0  525.0          394.0
    1         917.0    130.0    76.0    882.0   563.0    NaN          936.0
    2         344.0    376.0   960.0    442.0   247.0    NaN          819.0
    3         760.0    272.0     NaN    604.0   976.0    NaN          975.0
    4         745.0    199.0     NaN    512.0     NaN    NaN          123.0
    5         654.0    102.0     NaN    114.0     NaN    NaN          690.0
    6           NaN    570.0     NaN    318.0     NaN    NaN          568.0
    7           NaN    807.0     NaN    523.0     NaN    NaN          385.0
    8           NaN     18.0     NaN    890.0     NaN    NaN          451.0
    9           NaN     26.0     NaN    635.0     NaN    NaN          282.0
    10          NaN    871.0     NaN      NaN     NaN    NaN          771.0
    11          NaN    122.0     NaN      NaN     NaN    NaN          505.0
    12          NaN      0.0     NaN      NaN     NaN    NaN            NaN
    13          NaN    578.0     NaN      NaN     NaN    NaN            NaN
    

    【讨论】:

      【解决方案3】:

      pd.pivot 带你到一半,这里的问题是你的索引没有信息,所以你的非 NaN 值不在 df 的顶部

      df.pivot(index=None, columns='Country', values = 'Value')
      
      Country  Canada  England  France      ...        Mexico  Spain  United States
      0           NaN      NaN     NaN      ...           NaN    NaN          992.0
      1           NaN      NaN     NaN      ...           NaN    NaN          814.0
      2           NaN      NaN     NaN      ...           NaN    NaN          489.0
      3           NaN      NaN     NaN      ...           NaN    NaN          943.0
      4           NaN      NaN     NaN      ...           NaN    NaN          574.0
      5           NaN      NaN     NaN      ...           NaN    NaN          428.0
      6           NaN      NaN     NaN      ...           NaN    NaN          907.0
      7           NaN      NaN     NaN      ...           NaN    NaN          899.0
      8           NaN      NaN     NaN      ...           NaN    NaN          379.0
      9           NaN      NaN     NaN      ...           NaN    NaN          130.0
      

      【讨论】:

      • 您可以添加一列,其中包含您需要以类似索引的信息为中心的信息,例如df["num"] = df.groupby("Country").cumcount()。之后,将其用作枢轴中的索引应该可以正常工作。
      猜你喜欢
      • 2018-10-17
      • 2021-03-17
      • 1970-01-01
      • 1970-01-01
      • 2018-08-25
      • 1970-01-01
      • 2018-09-04
      • 1970-01-01
      • 2018-04-28
      相关资源
      最近更新 更多