2016-07-20 3 views
1

Моя цель состоит в том, чтобы иметь возможность группировать строки CSV-файла по значению столбца, а также выполнять обратную операцию. К примеру, желательно, чтобы быть в состоянии преобразовать назад и вперед между этими двумя форматами:Группировка и разгруппировка на основе столбца

uniqueId, groupId, feature_1, feature_2 
1, 100, text of 1, 10 
2, 100, some text of 2, 20 
3, 200, text of 3, 30 
4, 200, more text of 4, 40 
5, 100, another text of 5, 50 

Сгруппированного на GroupID:

uniqueId, groupId, feature_1, feature_2 
1|2|5, 100, text of 1|some text of 2|another text of 5, 10|20|50 
3|4, 200, text of 3|more text of 4, 30|40 

разделителя (здесь |) предполагаются не существуют где угодно в данных.

Я пытаюсь использовать Pandas для выполнения этого преобразования. Мой код до сих пор может получить доступ к ячейке строк, сгруппированных по groupId, но я не знаю, как заполнить новый dataframe.

Как мой метод может быть выполнен, чтобы выполнить преобразование в нужный новый df?

Как бы выглядел обратный метод, который преобразует новый df обратно в исходный?

Если R является лучшим инструментом для этой работы, я также открыт для предложений в R.

import pandas as pd 

def getGroupedDataFrame(df, groupByField, delimiter): 
''' Create a df with the rows grouped on groupByField, values separated by delimiter''' 
    groupIds = set(df[groupByField]) 
    df_copy = pd.DataFrame(index=groupIds,columns=df.columns) 
    # iterate over the different groupIds 
    for groupId in groupIds: 
     groupRows = df.loc[df[groupByField] == groupId] 
     # for all rows of the groupId 
     for index, row in groupRows.iterrows(): 
      # for all columns in the df 
      for column in df.columns: 
       print row[column] 
       # this prints the value the cell 
       # here append row[column] to its cell in the df_copy row of groupId, separated by delimiter 

ответ

4

Чтобы выполнить группировку, вы можете groupby на 'groupId', а затем внутри каждой группы выполняют объединение с ваш данный разделителем на каждой колонке:

def group_delim(grp, delim='|'): 
    """Join each columns within a group by the given delimiter.""" 
    return grp.apply(lambda col: delim.join(col)) 

# Make sure the DataFrame consists of strings, then apply grouping function. 
grouped = df.astype(str).groupby('groupId').apply(group_delim) 

# Drop the grouped groupId column, and replace it with the index groupId. 
grouped = grouped.drop('groupId', axis=1).reset_index() 

Сгруппированная выход:

groupId uniqueId         feature_1 feature_2 
0  100 1|2|5 text of 1|some text of 2|another text of 5 10|20|50 
1  200  3|4     text of 3|more text of 4  30|40 

Похожая идея для обратного процесса, но поскольку каждая строка представляет собой уникальную группу вы можете просто использовать обычный apply, нет необходимости в groupby:

def ungroup_delim(col, delim='|'): 
    """Split elements in a column by the given delimiter, stacking columnwise""" 
    return col.str.split(delim, expand=True).stack() 

# Apply the ungrouping function, and forward fill elements that aren't grouped. 
ungrouped = grouped.apply(ungroup_delim).ffill() 

# Drop the unwieldy altered index for a new one. 
ungrouped = ungrouped.reset_index(drop=True) 

и разгруппирование дает исходные данные:

groupId uniqueId   feature_1 feature_2 
0  100  1   text of 1  10 
1  100  2  some text of 2  20 
2  100  5 another text of 5  50 
3  200  3   text of 3  30 
4  200  4  more text of 4  40 

чтобы использовать различные разделители, вы бы просто передать delim в качестве аргумента apply:

foo.apply(group_delim, delim=';') 

В качестве побочного примечания, в общем, итерация по DataFrames происходит довольно медленно. По возможности вы захотите использовать векторный подход, как то, что я сделал выше.

+0

Я заметил, что в старой версии Панды для col.str.split (DELIM, расширение = True), расширение является не известный аргумент ключевого слова. Решение обходить это находится в http://stackoverflow.com/a/35567326/3229995 – tkja

2

Раствор в R:

я определить начальный кадр данных (для ясности)

df <- data.frame(uniqueID = c(1,2,3,4,5), 
      groupID = c(100,100,200,200,100), 
      feature_1 = c("text of 1","some text of 2", 
         "text of 3", "more text of 4", 
         "another text of 5"), 
      feature_2 = c(10,20,30,40,50), stringsAsFactors = F) 

Для получения сгруппированного кадра данных:

# Group and summarise using dplyr 
library(dplyr) 
grouped <- df %>% group_by(groupID) %>% summarise_each(funs(paste(.,collapse = "|"))) 

Выход:

grouped 

groupID uniqueID         feature_1 feature_2 
    (dbl) (chr)          (chr)  (chr) 
1  100 1|2|5 text of 1|some text of 2|another text of 5 10|20|50 
2  200  3|4     text of 3|more text of 4  30|40 

К ungrou р и вернуться к исходному кадру данных:

library(stringr) 
apply(grouped, 1, function(x) { 

     temp <- data.frame(str_split(x, '\\|'), stringsAsFactors = F) 
     colnames(temp) <- names(x) 
     temp 

     }) %>% 
     bind_rows() 

Выход:

groupID uniqueID   feature_1 feature_2 
    (chr) (chr)    (chr)  (chr) 
1  100  1   text of 1  10 
2  100  2 some text of 2  20 
3  100  5 another text of 5  50 
4  200  3   text of 3  30 
5  200  4 more text of 4  40 
Смежные вопросы