2016-05-27 4 views
0
city  state neighborhoods  categories 
Dravosburg PA  [asas,dfd]   ['Nightlife'] 
Dravosburg PA  [adad]    ['Auto_Repair','Automotive'] 

я выше dataframe Я хочу, чтобы преобразовать каждый элемент списка в столбец, например:Преобразование списка в панде dataframe в столбцы

city  state asas dfd adad Nightlife Auto_Repair Automotive 
Dravosburg PA 1  1 0 1   1   0  

Я использую следующий код, чтобы сделать это:

def list2columns(df): 
""" 
to convert list in the columns 
of a dataframe 
""" 
columns=['categories','neighborhoods'] 
for col in columns:  
    for i in range(len(df)): 
     for element in eval(df.loc[i,"categories"]): 
      if len(element)!=0: 
       if element not in df.columns: 
        df.loc[:,element]=0 
       else: 
        df.loc[i,element]=1 
  1. Как это сделать более эффективным способом?
  2. Почему до сих пор есть ниже предупреждения, когда я использую df.loc уже

    SettingWithCopyWarning: A value is trying to be set on a copy of a slice 
    from a DataFrame.Try using .loc[row_indexer,col_indexer] = value instead 
    

ответ

2

Поскольку вы используете eval(), я полагаю, каждый столбец имеет строковое представление списка, а не список. Кроме того, в отличие от вашего примера выше, я предполагаю, что в столбцах neighborhoods есть котировки вокруг элементов (df.iloc[0, 'neighborhoods'] == "['asas','dfd']"), потому что иначе ваш eval() не сработает.

Если это все правильно, вы могли бы попробовать что-то вроде этого:

def list2columns(df): 
""" 
to convert list in the columns of a dataframe 
""" 
columns = ['categories','neighborhoods'] 
new_cols = set()  # list of all new columns added 
for col in columns:  
    for i in range(len(df[col])): 
     # get the list of columns to set 
     set_cols = eval(df.iloc[i, col]) 
     # set the values of these columns to 1 in the current row 
     # (if this causes new columns to be added, other rows will get nans) 
     df.iloc[i, set_cols] = 1 
     # remember which new columns have been added 
     new_cols.update(set_cols) 
# convert any un-set values in the new columns to 0 
df[list(new_cols)].fillna(value=0, inplace=True) 
# if that doesn't work, this may: 
# df.update(df[list(new_cols)].fillna(value=0)) 

Я могу только предполагать, ответ на ваш второй вопрос, о предупреждении SettingWithCopy.

Возможно (но маловероятно), что использование df.iloc вместо df.loc поможет, так как предназначено для выбора по номеру строки (в вашем случае, df.loc[i, col] работает только потому, что вы не установили индекс, поэтому панда использует по умолчанию index, который соответствует номеру строки).

Другая возможность заключается в том, что df, который передается вашей функции, уже является срезом из более крупного блока данных, и это вызывает предупреждение SettingWithCopy.

Я также обнаружил, что использование df.loc со смешанными режимами индексирования (логические селекторы для строк и имен столбцов для столбцов) вызывает предупреждение SettingWithCopy; возможно, что ваши селектора срезов вызывают подобные проблемы.

Надеемся, что более простая и более прямая индексация в коде выше решит любую из этих проблем. Но, пожалуйста, сообщите об этом (и укажите код для генерации df), если вы все еще видите это предупреждение.

2

Используйте это вместо

def list2columns(df): 
    """ 
    to convert list in the columns 
    of a dataframe 
    """ 
    df = df.copy() 
    columns=['categories','neighborhoods'] 
    for col in columns:  
     for i in range(len(df)): 
      for element in eval(df.loc[i,"categories"]): 
       if len(element)!=0: 
        if element not in df.columns: 
         df.loc[:,element]=0 
        else: 
         df.loc[i,element]=1 
    return df