Python Pandas 合并数据框中相同名称的列
我有几个CSV文件在处理,但其中有些文件的列名是重复的。
比如我可能会有一个这样的CSV文件:
ID Name a a a b b
1 test1 1 NaN NaN "a" NaN
2 test2 NaN 2 NaN "a" NaN
3 test3 2 3 NaN NaN "b"
4 test4 NaN NaN 4 NaN "b"
当我把它加载到pandas里时,结果是这样的:
ID Name a a.1 a.2 b b.1
1 test1 1 NaN NaN "a" NaN
2 test2 NaN 2 NaN "a" NaN
3 test3 2 3 NaN NaN "b"
4 test4 NaN NaN 4 NaN "b"
我想做的是把那些同名的列合并成一列(如果有多个值的话,保持这些值分开),我理想的输出结果是这样的:
ID Name a b
1 test1 "1" "a"
2 test2 "2" "a"
3 test3 "2;3" "b"
4 test4 "4" "b"
所以我在想,这样做是否可能呢?
5 个回答
1
如果你想要修补(更新)数据框(Dataframe),你可以这样做:
# consolidated columns, replacing instead of joining by ;
s_fixed_a = df['a'].fillna(df['a.1']).fillna(df['a.2'])
s_fixed_b = df['b'].fillna(df['b.1'])
# create new df
df_resulting = df[['Id', 'Name']].merge(s_fixed_a, left_index=True, right_index=True).merge(s_fixed_b, left_index=True, right_index=True)
3
接着之前的一个回答说一下:从read_csv读取的数据中,列名后面会加上后缀,让它们变得独一无二,比如你看到的a.0、a.1、a.2等等。
你可能需要给group_by传递一个函数,以便处理这些情况,比如:
df = pd.read_csv('data.csv') #csv file with multiple columns of the same name
#function to join columns if column is not null
def sjoin(x): return ';'.join(x[x.notnull()].astype(str))
#function to ignore the suffix on the column e.g. a.1, a.2 will be grouped together
def groupby_field(col):
parts = col.split('.')
return '{}'.format(parts[0])
df = df.groupby(groupby_field, axis=1,).apply(lambda x: x.apply(sjoin, axis=1))
5
当然,DSM和CT Zhu的回答非常简洁,充分利用了Python和数据框(dataframe)的一些内置功能。不过,我这里的解释可能会稍微长一些 -- [咳嗽] --。
def myJoiner(row):
newrow = []
for r in row:
if not pandas.isnull(r):
newrow.append(str(r))
return ';'.join(newrow)
def groupCols(df, key):
columns = df.select(lambda col: key in col, axis=1)
joined = columns.apply(myJoiner, axis=1)
joined.name = key
return pandas.DataFrame(joined)
import pandas
from io import StringIO # python 3.X
#from StringIO import StringIO #python 2.X
data = StringIO("""\
ID Name a a a b b
1 test1 1 NaN NaN "a" NaN
2 test2 NaN 2 NaN "a" NaN
3 test3 2 3 NaN NaN "b"
4 test4 NaN NaN 4 NaN "b"
""")
df = pandas.read_table(data, sep='\s+')
df.set_index(['ID', 'Name'], inplace=True)
AB = groupCols(df, 'a').join(groupCols(df, 'b'))
print(AB)
这样我得到了:
a b
ID Name
1 test1 1.0 a
2 test2 2.0 a
3 test3 2.0;3.0 b
4 test4 4.0 b
5
可能有重复的列名并不是个好主意,但这样做也是可以的:
In [72]:
df2=df[['ID', 'Name']]
df2['a']='"'+df.T[df.columns.values=='a'].apply(lambda x: ';'.join(["%i"%item for item in x[x.notnull()]]))+'"' #these columns are of float dtype
df2['b']=df.T[df.columns.values=='b'].apply(lambda x: ';'.join([item for item in x[x.notnull()]])) #these columns are of objects dtype
print df2
ID Name a b
0 1 test1 "1" "a"
1 2 test2 "2" "a"
2 3 test3 "2;3" "b"
3 4 test4 "4" "b"
[4 rows x 4 columns]
16
你可以在axis=1
上使用groupby
,然后试试下面这样的写法:
>>> def sjoin(x): return ';'.join(x[x.notnull()].astype(str))
>>> df.groupby(level=0, axis=1).apply(lambda x: x.apply(sjoin, axis=1))
ID Name a b
0 1 test1 1.0 a
1 2 test2 2.0 a
2 3 test3 2.0;3.0 b
3 4 test4 4.0 b
在这里,你可以用你想要的任何格式化操作符,代替.astype(str)
。