Pandas - создает отдельные столбцы в DataFrame на основе значений определенного столбца - PullRequest
0 голосов
/ 03 сентября 2018

Допустим, у меня есть простой DataFrame Pandas, где один столбец содержит название страны, а другой столбец содержит некоторое значение. Например:

# 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

Мой вопрос заключается в том, как проще всего преобразовать этот DataFrame в тот, в котором у каждой страны есть свой собственный столбец, и все значения этой страны перечислены в этом столбце? Другими словами, как я могу легко создать DataFrame, где количество столбцов - это уникальное число стран в столбце «Страна», а длина каждого столбца будет варьироваться в зависимости от того, сколько раз соответствующая страна появляется в исходном 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?

Спасибо!

Ответы [ 3 ]

0 голосов
/ 03 сентября 2018

Возможно, это не самое эффективное решение, но оно оправдывает все.

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 и вывод разворота 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
0 голосов
/ 03 сентября 2018

Используйте groupby, cumcount и unstack с T:

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
0 голосов
/ 03 сентября 2018

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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...