Concat список фрейма данных pandas, но игнорируя имя столбца

Подзаголовок: Тупые панды, перестаньте умничать.

У меня есть список (res) фреймов данных pandas с одним столбцом, каждый из которых содержит одинаковые числовые данные, но каждый с другим именем столбца. Индексы строк не имеют значения. Я хочу поместить их в один очень длинный фрейм данных с одним столбцом.

Когда я делаю pd.concat(res), я получаю один столбец для каждого входного файла (и загружаю и загружаю ячейки NaN). Я пробовал разные значения для параметров (*), но ни один из них не делает то, что мне нужно.

Изменить: Пример данных:

res = [
    pd.DataFrame({'A':[1,2,3]}),
    pd.DataFrame({'B':[9,8,7,6,5,4]}),
    pd.DataFrame({'C':[100,200,300,400]}),
]

У меня есть уродливое решение: скопировать каждый фрейм данных и присвоить ему новое имя столбца:

newList = []
for r in res:
  r.columns = ["same"]
  newList.append(r)
pd.concat( newList, ignore_index=True )

Наверняка это не лучший способ сделать это??

Кстати, pandas: кадр данных concat с другим именем столбца похож, но мой вопрос еще проще, так как я не хотите, чтобы индекс сохранялся. (Я также начинаю со списка из N фреймов данных с одним столбцом, а не с одного фрейма данных из N столбцов.)

*: например. axis=0 — поведение по умолчанию. axis=1 выдает ошибку. join="inner" просто глупо (я получаю только индекс). ignore_index=True перенумеровывает индекс, но я все еще получаю много столбцов, много NaN.


ОБНОВЛЕНИЕ для пустых списков

У меня были проблемы (со всеми указанными решениями), когда у данных был пустой список, например:

res = [
    pd.DataFrame({'A':[1,2,3]}),
    pd.DataFrame({'B':[9,8,7,6,5,4]}),
    pd.DataFrame({'C':[]}),
    pd.DataFrame({'D':[100,200,300,400]}),
]

Хитрость заключалась в том, чтобы форсировать тип, добавляя .astype('float64'). Например.

pd.Series(np.concatenate([df.values.ravel().astype('float64') for df in res]))

or:

pd.concat(res,axis=0).astype('float64').stack().reset_index(drop=True)

person Darren Cook    schedule 19.12.2016    source источник


Ответы (2)


Я бы использовал такое понимание списка:

import pandas as pd
res = [
    pd.DataFrame({'A':[1,2,3]}),
    pd.DataFrame({'B':[9,8,7,6,5,4]}),
    pd.DataFrame({'C':[100,200,300,400]}),
]


x = []
[x.extend(df.values.tolist()) for df in res]
pd.DataFrame(x)

Out[49]: 
      0
0     1
1     2
2     3
3     9
4     8
5     7
6     6
7     5
8     4
9   100
10  200
11  300
12  400

Я проверил скорость для вас.

%timeit x = []; [x.extend(df.values.tolist()) for df in res]; pd.DataFrame(x)
10000 loops, best of 3: 196 µs per loop
%timeit pd.Series(pd.concat(res, axis=1).values.ravel()).dropna()
1000 loops, best of 3: 920 µs per loop
%timeit pd.concat(res, axis=1).stack().reset_index(drop=True)
1000 loops, best of 3: 902 µs per loop
%timeit pd.DataFrame(pd.concat(res, axis=1).values.ravel(), columns=['col']).dropna()
1000 loops, best of 3: 1.07 ms per loop
%timeit pd.Series(np.concatenate([df.values.ravel() for df in res]))
10000 loops, best of 3: 70.2 µs per loop

похоже

pd.Series(np.concatenate([df.values.ravel() for df in res]))

является самым быстрым.

person Steven G    schedule 19.12.2016
comment
Может быть pd.concat([x.rename(columns=lambda c: 'same') for x in res], ignore_index=True) - person jrovegno; 20.12.2016
comment
Спасибо за сроки; в данном случае это не было чувствительным ко времени, но полезно знать самую быструю идиому на случай, если она мне когда-нибудь понадобится для большого объема данных. - person Darren Cook; 24.12.2016

Я думаю, вам нужно concat с stack:

print (pd.concat(res, axis=1))
     A  B      C
0  1.0  9  100.0
1  2.0  8  200.0
2  3.0  7  300.0
3  NaN  6  400.0
4  NaN  5    NaN
5  NaN  4    NaN

print (pd.concat(res, axis=1).stack().reset_index(drop=True))
0       1.0
1       9.0
2     100.0
3       2.0
4       8.0
5     200.0
6       3.0
7       7.0
8     300.0
9       6.0
10    400.0
11      5.0
12      4.0
dtype: float64

Другое решение с numpy.ravel для выравнивания:

print (pd.Series(pd.concat(res, axis=1).values.ravel()).dropna())
0       1.0
1       9.0
2     100.0
3       2.0
4       8.0
5     200.0
6       3.0
7       7.0
8     300.0
10      6.0
11    400.0
13      5.0
16      4.0
dtype: float64

print (pd.DataFrame(pd.concat(res, axis=1).values.ravel(), columns=['col']).dropna())
      col
0     1.0
1     9.0
2   100.0
3     2.0
4     8.0
5   200.0
6     3.0
7     7.0
8   300.0
10    6.0
11  400.0
13    5.0
16    4.0

Решение с list comprehension:

print (pd.Series(np.concatenate([df.values.ravel() for df in res])))
0       1
1       2
2       3
3       9
4       8
5       7
6       6
7       5
8       4
9     100
10    200
11    300
12    400
dtype: int64 
person jezrael    schedule 19.12.2016
comment
В том же духе, но у меня есть список фреймов данных с 1 столбцом, а не фрейм данных с 6 столбцами в вашем примере. - person Darren Cook; 19.12.2016
comment
Я только что добавил образцы данных к вопросу. - person Darren Cook; 19.12.2016
comment
Спасибо. Я только что обновил свои образцы данных (кадры имеют разное количество строк), так как мой вывод pd.concat(res) был не таким хорошим, как ваш. Но ваш первый ответ работает и для этого. (Решение ravel не работает - NaN выживают; я мог бы добавить .dropna().reset_index(drop=True), но...) - person Darren Cook; 19.12.2016