python перекодировать csv с условием - PullRequest
0 голосов
/ 23 января 2020

Я новичок в python. Мне нужно перекодировать CSV-файл:

unique_id,pid,Age
1,1,1
1,2,3
2,1,5
2,2,6
3,1,6
3,2,4
3,3,6
3,4,1
3,5,4
4,1,6
4,2,5

Условие таково: для каждого [уникального_идентификатора], если есть какой-либо [Возраст] == 6, поместите значение 1 в соответствующие строки с [pid] = 1, остальные должны быть 0.

выходной CSV будет выглядеть следующим образом:

unique_id,pid,Age,recode
1,1,1,0
1,2,3,0
2,1,5,1
2,2,6,0
3,1,6,1
3,2,4,0
3,3,6,0
3,4,1,0
3,5,4,0
4,1,6,1
4,2,5,0

Я использовал numpy: например, следующее:

import numpy
input_file1 = "data.csv"
input_folder = 'G:/My Drive/'
Her_HH =pd.read_csv(input_folder + input_file1)
Her_HH['recode'] = numpy.select([Her_PP['Age']==6,Her_PP['Age']<6], [1,0], default=Her_HH['recode'])

Her_HH.to_csv('recode_elderly.csv', index=False)

но это не ставит значение 1, где [pid] равен 1. Любая помощь будет оценена.

Ответы [ 2 ]

1 голос
/ 24 января 2020

Вы можете использовать DataFrame.assign для нового столбца с GroupBy.transform для теста, если хотя бы одно совпадение по GroupBy.any, маска цепи для теста 1 с & для побитового И и последним приведением к целым числам

#sorting if necessary
df = df.sort_values('unique_id')

m1 = df.assign(test=df['Age'] == 6).groupby('unique_id')['test'].transform('any')

Еще одна идея для получения групп с 6 - отфильтровать их с unique_id и Series.isin:

m1 = df['unique_id'].isin(df.loc[df['Age'] == 6, 'unique_id'])

m2 = df['pid'] == 1

df['recode'] = (m1 & m2).astype(int)
print (df)
    unique_id  pid  Age  recode
0           1    1    1       0
1           1    2    3       0
2           2    1    5       1
3           2    2    6       0
4           3    1    6       1
5           3    2    4       0
6           3    3    6       0
7           3    4    1       0
8           3    5    4       0
9           4    1    6       1
10          4    2    5       0

РЕДАКТИРОВАТЬ:

Для групп проверки без совпадения 6 в столбце Возраст возможна фильтрация по инвертированной маске по ~ и, если хотите, только все уникальные строки по unique_id значения добавить DataFrame.drop_duplicates:

print (df[~m1])
   unique_id  pid  Age
0          1    1    1
1          1    2    3

df1 = df[~m1].drop_duplicates('unique_id')
print (df1)
   unique_id  pid  Age
0          1    1    1
0 голосов
/ 24 января 2020

Это немного неуклюже, так как я знаю numpy намного лучше, чем pandas.

Загрузите ваш CSV-образец в фрейм данных:

In [205]: df = pd.read_csv('stack59885878.csv')                                                  
In [206]: df                                                                                     
Out[206]: 
    unique_id  pid  Age
0           1    1    1
1           1    2    3
2           2    1    5
3           2    2    6
4           3    1    6
5           3    2    4
6           3    3    6
7           3    4    1
8           3    5    4
9           4    1    6
10          4    2    5

Создайте groupby объект, основанный на столбце unique_id:

In [207]: gps = df.groupby('unique_id')                                                          

In [209]: gps.groups                                                                             
Out[209]: 
{1: Int64Index([0, 1], dtype='int64'),
 2: Int64Index([2, 3], dtype='int64'),
 3: Int64Index([4, 5, 6, 7, 8], dtype='int64'),
 4: Int64Index([9, 10], dtype='int64')}

Я видел pandas способов итерации по группам, но вот понимание списка. Итерация создает кортеж с идентификатором и фреймом данных. Мы хотим протестировать каждый фрейм данных группы для значений 'Age' и 'pid':

In [211]: recode_values = [(gp['Age']==6).any() & (gp['pid']==1) for x, gp in gps]               
In [212]: recode_values                                                                          
Out[212]: 
[0    False
 1    False
 Name: pid, dtype: bool, 2     True
 3    False
 Name: pid, dtype: bool, 4     True
 5    False
 6    False
 7    False
 8    False
 Name: pid, dtype: bool, 9      True
 10    False
 Name: pid, dtype: bool]

В результате получается список Series, с True, где pid равно 1, и есть 'Age' 6 в группе.

Объединение этих серий с numpy.hstack создает логический массив, который мы можем преобразовать в целочисленный массив:

In [214]: np.hstack(recode_values)                                                               
Out[214]: 
array([False, False,  True, False,  True, False, False, False, False,
        True, False])
In [215]: df['recode']=_.astype(int)            # assign that to a new column
In [216]: df                                                                                     
Out[216]: 
    unique_id  pid  Age  recode
0           1    1    1       0
1           1    2    3       0
2           2    1    5       1
3           2    2    6       0
4           3    1    6       1
5           3    2    4       0
6           3    3    6       0
7           3    4    1       0
8           3    5    4       0
9           4    1    6       1
10          4    2    5       0

Опять же, я думаю, что есть идиоматизм c pandas способ присоединиться к этим сериям. Но на данный момент это работает.

===

ОК, объект groupby имеет apply:

In [223]: def foo(gp): 
     ...:     return (gp['Age']==6).any() & (gp['pid']==1).astype(int) 
     ...:                                                                                        
In [224]: gps.apply(foo)                                                                         
Out[224]: 
unique_id    
1          0     0
           1     0
2          2     1
           3     0
3          4     1
           5     0
           6     0
           7     0
           8     0
4          9     1
           10    0
Name: pid, dtype: int64

И удаляет мультииндексирование с помощью:

In [242]: gps.apply(foo).reset_index(0, True)                                                    
Out[242]: 
0     0
1     0
2     1
3     0
4     1
5     0
6     0
7     0
8     0
9     1
10    0
Name: pid, dtype: int64
In [243]: df['recode']=_     # and assign to recode

Много экспериментов и обучения здесь.

...