Объедините три столбца в один в CSV-файле с питоном и пандами - PullRequest
0 голосов
/ 13 мая 2018

Привет. Я пытаюсь объединить несколько существующих столбцов в 1 новый столбец, а затем удалить три исходных в файле CSV. Я пытался сделать это с пандами, но мне не повезло. Я довольно новичок в питоне.

Мой код сначала объединяет несколько файлов CSV в одном каталоге, а затем пытается манипулировать столбцами. Первый комбинат работает, и я получаю файл output.csv с объединенными данными, однако комбинат столбцов - нет.

import glob
import pandas as pd

interesting_files = glob.glob("*.csv")

header_saved = False
with open('output.csv','wb') as fout:
    for filename in interesting_files:
        with open(filename) as fin:
            header = next(fin)
            if not header_saved:
                fout.write(header)
                header_saved = True
            for line in fin:
                fout.write(line)

df = pd.read_csv("output.csv")
df['HostAffected']=df['Host'] + "/" + df['Protocol'] + "/" + df['Port']
df.to_csv("newoutput.csv")

Эффективно превращая это:

Host,Protocol,Port
10.0.0.10,tcp,445
10.0.0.10,tcp,445
10.0.0.10,tcp,445
10.0.0.10,tcp,445
10.0.0.10,tcp,445
10.0.0.10,tcp,445
10.0.0.10,tcp,445
10.0.0.10,tcp,49707
10.0.0.10,tcp,49672
10.0.0.10,tcp,49670

примерно так:

HostsAffected
10.0.0.10/tcp/445
10.0.0.10/tcp/445
10.0.0.10/tcp/445
10.0.0.10/tcp/445
10.0.0.10/tcp/445
10.0.0.10/tcp/445
10.0.0.11/tcp/445
10.0.0.11/tcp/49707
10.0.0.11/tcp/49672
10.0.0.11/tcp/49670
10.0.0.11/tcp/49668
10.0.0.11/tcp/49667

Однако в csv есть и другие столбцы.

Я не кодер, я просто пытаюсь решить проблему, любая помощь очень ценится.

Ответы [ 3 ]

0 голосов
/ 13 мая 2018

Есть несколько способов сделать это: либо использовать векторизованные функции для объединения серий, либо использовать функцию lambda с pd.Series.apply.

Векторизованный раствор

Не забудьте привести нечисловые типы как str.

df['HostAffected'] = df['Host'] + '/' + df['Protocol'] + '/' + df['Port'].map(str)

Замечание по производительности: Преобразование серии целых чисел в строки - почему применяется намного быстрее, чем astype?

Применить lambda функция

df['HostsAffected'] = df.apply(lambda x: '/'.join(list(map(str, x))), axis=1)

В обоих решениях вы можете просто отфильтровать по этому столбцу, чтобы удалить все остальные:

df = df[['HostsAffected']]

Полный пример

from io import StringIO
import pandas as pd

mystr = StringIO("""Host,Protocol,Port
10.0.0.10,tcp,445
10.0.0.10,tcp,445
10.0.0.10,tcp,445
10.0.0.10,tcp,445
10.0.0.10,tcp,445
10.0.0.10,tcp,445
10.0.0.10,tcp,445
10.0.0.10,tcp,49707
10.0.0.10,tcp,49672
10.0.0.10,tcp,49670""")

# replace mystr with 'file.csv'
df = pd.read_csv(mystr)

# combine columns
df['HostsAffected'] = df['Host'] + '/' + df['Protocol'] + '/' + df['Port'].map(str)

# include only new columns
df = df[['HostsAffected']]

Результат:

print(df)

         HostsAffected
0    10.0.0.10/tcp/445
1    10.0.0.10/tcp/445
2    10.0.0.10/tcp/445
3    10.0.0.10/tcp/445
4    10.0.0.10/tcp/445
5    10.0.0.10/tcp/445
6    10.0.0.10/tcp/445
7  10.0.0.10/tcp/49707
8  10.0.0.10/tcp/49672
9  10.0.0.10/tcp/49670
0 голосов
/ 13 мая 2018

На мой взгляд, у нас есть три варианта:

%timeit df['Host'] + "/" + df['Protocol'] + "/" + df['Port'].map(str)
%timeit ['/'.join(i) for i in zip(df['Host'],df['Protocol'],df['Port'].map(str))]
%timeit ['/'.join(i) for i in df[['Host','Protocol','Port']].astype(str).values]

Задержка

10 loops, best of 3: 39.7 ms per loop  
10 loops, best of 3: 35.9 ms per loop  
10 loops, best of 3: 162 ms per loop

Каким бы медленным я не думал, что это будет ваш самый читаемый подход:

import pandas as pd

data = '''\
ID,Host,Protocol,Port
1,10.0.0.10,tcp,445
1,10.0.0.10,tcp,445
1,10.0.0.10,tcp,445
1,10.0.0.10,tcp,445
1,10.0.0.10,tcp,445
1,10.0.0.10,tcp,445
1,10.0.0.10,tcp,445
1,10.0.0.10,tcp,49707
1,10.0.0.10,tcp,49672
1,10.0.0.10,tcp,49670'''

df = pd.read_csv(pd.compat.StringIO(data)) # Recreates a sample dataframe

cols = ['Host','Protocol','Port']
newcol = ['/'.join(i) for i in df[cols].astype(str).values]
df = df.assign(HostAffected=newcol).drop(cols, 1)
print(df)

Возвращает:

   ID         HostAffected
0   1    10.0.0.10/tcp/445
1   1    10.0.0.10/tcp/445
2   1    10.0.0.10/tcp/445
3   1    10.0.0.10/tcp/445
4   1    10.0.0.10/tcp/445
5   1    10.0.0.10/tcp/445
6   1    10.0.0.10/tcp/445
7   1  10.0.0.10/tcp/49707
8   1  10.0.0.10/tcp/49672
9   1  10.0.0.10/tcp/49670
0 голосов
/ 13 мая 2018

Вот как вы можете это сделать:

    dt = """Host,Protocol,Port
10.0.0.10,tcp,445
10.0.0.10,tcp,445
10.0.0.10,tcp,445
10.0.0.10,tcp,445
10.0.0.10,tcp,445
10.0.0.10,tcp,445
10.0.0.10,tcp,445
10.0.0.10,tcp,49707
10.0.0.10,tcp,49672
10.0.0.10,tcp,49670"""

tdf = pd.read_csv(pd.compat.StringIO(dt))
tdf['HostsAffected'] = tdf.apply(lambda x: '{}/{}/{}'.format(x['Host'] , x['Protocol'] , x['Port']), axis=1)
tdf = tdf[['HostsAffected']]
tdf.to_csv(<path-to-save-csv-file>)

Это будет вывод:

    HostsAffected
0   10.0.0.10/tcp/445
1   10.0.0.10/tcp/445
2   10.0.0.10/tcp/445
3   10.0.0.10/tcp/445
4   10.0.0.10/tcp/445
5   10.0.0.10/tcp/445
6   10.0.0.10/tcp/445
7   10.0.0.10/tcp/49707
8   10.0.0.10/tcp/49672
9   10.0.0.10/tcp/49670

Если вы читаете CSV из файла, отредактируйте строку read_csv какследует:

tdf = pd.read_csv(<path-to-the-file>)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...