Когда вы говорите несколько запросов, вы имеете в виду несколько операторов SQL, например:
UPDATE table1 SET a=b WHERE c;
UPDATE table2 SET a=b WHERE d;
UPDATE table3 SET a=b WHERE e;
Или несколько вызовов функций запроса, как в:
mySqlQuery(UPDATE table1 SET a=b WHERE c;)
mySqlQuery(UPDATE table2 SET a=b WHERE d;)
mySqlQuery(UPDATE table3 SET a=b WHERE e;)
сделанный с помощью одного вызова mySqlQuery, если это то, чего вы хотели достичь, просто вызовите функцию mySqlQuery следующим образом:
mySqlQuery(UPDATE table1 SET a=b WHERE c; UPDATE table2 SET a=b WHERE d; UPDATE table3 SET a=b WHERE e;)
Это выполнит все три запроса одним вызовом mySqlQuery ().
Как насчет чего-то вроде этого:
In [55]: pd.concat([Series(row['var2'], row['var1'].split(','))
for _, row in a.iterrows()]).reset_index()
Out[55]:
index 0
0 a 1
1 b 1
2 c 1
3 d 2
4 e 2
5 f 2
Тогда вам просто нужно переименовать столбцы
Другое решение, использующее пакет копирования python
import copy
new_observations = list()
def pandas_explode(df, column_to_explode):
new_observations = list()
for row in df.to_dict(orient='records'):
explode_values = row[column_to_explode]
del row[column_to_explode]
if type(explode_values) is list or type(explode_values) is tuple:
for explode_value in explode_values:
new_observation = copy.deepcopy(row)
new_observation[column_to_explode] = explode_value
new_observations.append(new_observation)
else:
new_observation = copy.deepcopy(row)
new_observation[column_to_explode] = explode_values
new_observations.append(new_observation)
return_df = pd.DataFrame(new_observations)
return return_df
df = pandas_explode(df, column_name)
Функция разделения строк может принимать опцию логического аргумента «expand».
Вот решение, использующее этот аргумент:
a.var1.str.split(",",expand=True).set_index(a.var2).stack().reset_index(level=1, drop=True).reset_index().rename(columns={0:"var1"})
Похожие вопросы как: pandas: Как разделить текст в столбце на несколько строк?
Вы могли бы сделать:
>> a=pd.DataFrame({"var1":"a,b,c d,e,f".split(),"var2":[1,2]})
>> s = a.var1.str.split(",").apply(pd.Series, 1).stack()
>> s.index = s.index.droplevel(-1)
>> del a['var1']
>> a.join(s)
var2 var1
0 1 a
0 1 b
0 1 c
1 2 d
1 2 e
1 2 f
s.name = 'var1'
– Jesse
4 June 2017 в 07:13
Просто использовал превосходный ответ jiln сверху, но ему нужно было расширить, чтобы разделить несколько столбцов. Думаю, я бы поделился.
def splitDataFrameList(df,target_column,separator):
''' df = dataframe to split,
target_column = the column containing the values to split
separator = the symbol used to perform the split
returns: a dataframe with each entry for the target column separated, with each element moved into a new row.
The values in the other columns are duplicated across the newly divided rows.
'''
def splitListToRows(row, row_accumulator, target_columns, separator):
split_rows = []
for target_column in target_columns:
split_rows.append(row[target_column].split(separator))
# Seperate for multiple columns
for i in range(len(split_rows[0])):
new_row = row.to_dict()
for j in range(len(split_rows)):
new_row[target_columns[j]] = split_rows[j][i]
row_accumulator.append(new_row)
new_rows = []
df.apply(splitListToRows,axis=1,args = (new_rows,target_column,separator))
new_df = pd.DataFrame(new_rows)
return new_df
После болезненных экспериментов, чтобы найти что-то быстрее, чем принятый ответ, я получил это, чтобы работать. Он работал примерно в 100 раз быстрее в наборе данных, на котором я его пробовал.
Если кто-то знает способ сделать это более элегантным, обязательно измените мой код. Я не мог найти способ, который работает без установки других столбцов, которые вы хотите сохранить в качестве индекса, а затем сбросить индекс и переименовать столбцы, но я бы предположил, что есть что-то еще, что работает.
b = DataFrame(a.var1.str.split(',').tolist(), index=a.var2).stack()
b = b.reset_index()[[0, 'var2']] # var1 variable is currently labeled 0
b.columns = ['var1', 'var2'] # renaming var1
Я придумал решение для dataframes с произвольным количеством столбцов (в то же время только разделяя записи по одному столбцу за раз).
def splitDataFrameList(df,target_column,separator):
''' df = dataframe to split,
target_column = the column containing the values to split
separator = the symbol used to perform the split
returns: a dataframe with each entry for the target column separated, with each element moved into a new row.
The values in the other columns are duplicated across the newly divided rows.
'''
def splitListToRows(row,row_accumulator,target_column,separator):
split_row = row[target_column].split(separator)
for s in split_row:
new_row = row.to_dict()
new_row[target_column] = s
row_accumulator.append(new_row)
new_rows = []
df.apply(splitListToRows,axis=1,args = (new_rows,target_column,separator))
new_df = pandas.DataFrame(new_rows)
return new_df
UPDATE2: более общая векторная функция, которая будет работать для нескольких normal
и нескольких столбцов list
def explode(df, lst_cols, fill_value=''):
# make sure `lst_cols` is a list
if lst_cols and not isinstance(lst_cols, list):
lst_cols = [lst_cols]
# all columns except `lst_cols`
idx_cols = df.columns.difference(lst_cols)
# calculate lengths of lists
lens = df[lst_cols[0]].str.len()
if (lens > 0).all():
# ALL lists in cells aren't empty
return pd.DataFrame({
col:np.repeat(df[col].values, lens)
for col in idx_cols
}).assign(**{col:np.concatenate(df[col].values) for col in lst_cols}) \
.loc[:, df.columns]
else:
# at least one list in cells is empty
return pd.DataFrame({
col:np.repeat(df[col].values, lens)
for col in idx_cols
}).assign(**{col:np.concatenate(df[col].values) for col in lst_cols}) \
.append(df.loc[lens==0, idx_cols]).fillna(fill_value) \
.loc[:, df.columns]
Демо:
Несколько list
столбцов - все list
столбцы должны иметь одинаковые элементы из каждой строки:
In [36]: df
Out[36]:
aaa myid num text
0 10 1 [1, 2, 3] [aa, bb, cc]
1 11 2 [1, 2] [cc, dd]
2 12 3 [] []
3 13 4 [] []
In [37]: explode(df, ['num','text'], fill_value='')
Out[37]:
aaa myid num text
0 10 1 1 aa
1 10 1 2 bb
2 10 1 3 cc
3 11 2 1 cc
4 11 2 2 dd
2 12 3
3 13 4
Настройка:
df = pd.DataFrame({
'aaa': {0: 10, 1: 11, 2: 12, 3: 13},
'myid': {0: 1, 1: 2, 2: 3, 3: 4},
'num': {0: [1, 2, 3], 1: [1, 2], 2: [], 3: []},
'text': {0: ['aa', 'bb', 'cc'], 1: ['cc', 'dd'], 2: [], 3: []}
})
Столбец CSV:
In [46]: df
Out[46]:
var1 var2 var3
0 a,b,c 1 XX
1 d,e,f,x,y 2 ZZ
In [47]: explode(df.assign(var1=df.var1.str.split(',')), 'var1')
Out[47]:
var1 var2 var3
0 a 1 XX
1 b 1 XX
2 c 1 XX
3 d 2 ZZ
4 e 2 ZZ
5 f 2 ZZ
6 x 2 ZZ
7 y 2 ZZ
используя этот небольшой трюк, мы можем преобразовать CSV-подобный столбец в столбец list
:
In [48]: df.assign(var1=df.var1.str.split(','))
Out[48]:
var1 var2 var3
0 [a, b, c] 1 XX
1 [d, e, f, x, y] 2 ZZ
UPDATE: общий векторный подход (будет работать и для нескольких столбцов):
Original DF:
In [177]: df
Out[177]:
var1 var2 var3
0 a,b,c 1 XX
1 d,e,f,x,y 2 ZZ
Решение:
сначала давайте преобразуем строки CSV в списки:
In [178]: lst_col = 'var1'
In [179]: x = df.assign(**{lst_col:df[lst_col].str.split(',')})
In [180]: x
Out[180]:
var1 var2 var3
0 [a, b, c] 1 XX
1 [d, e, f, x, y] 2 ZZ
Теперь мы можем это сделать:
In [181]: pd.DataFrame({
...: col:np.repeat(x[col].values, x[lst_col].str.len())
...: for col in x.columns.difference([lst_col])
...: }).assign(**{lst_col:np.concatenate(x[lst_col].values)})[x.columns.tolist()]
...:
Out[181]:
var1 var2 var3
0 a 1 XX
1 b 1 XX
2 c 1 XX
3 d 2 ZZ
4 e 2 ZZ
5 f 2 ZZ
6 x 2 ZZ
7 y 2 ZZ
OLD answer:
Вдохновленный решением @AFinkelstein , я хотел сделать его более обобщенным, что может быть применено к DF с более чем два столбца и так же быстро, но почти так же быстро, как и решение Апинкельштейна):
In [2]: df = pd.DataFrame(
...: [{'var1': 'a,b,c', 'var2': 1, 'var3': 'XX'},
...: {'var1': 'd,e,f,x,y', 'var2': 2, 'var3': 'ZZ'}]
...: )
In [3]: df
Out[3]:
var1 var2 var3
0 a,b,c 1 XX
1 d,e,f,x,y 2 ZZ
In [4]: (df.set_index(df.columns.drop('var1',1).tolist())
...: .var1.str.split(',', expand=True)
...: .stack()
...: .reset_index()
...: .rename(columns={0:'var1'})
...: .loc[:, df.columns]
...: )
Out[4]:
var1 var2 var3
0 a 1 XX
1 b 1 XX
2 c 1 XX
3 d 2 ZZ
4 e 2 ZZ
5 f 2 ZZ
6 x 2 ZZ
7 y 2 ZZ
Я придумал следующее решение этой проблемы:
def iter_var1(d):
for _, row in d.iterrows():
for v in row["var1"].split(","):
yield (v, row["var2"])
new_a = DataFrame.from_records([i for i in iter_var1(a)],
columns=["var1", "var2"])
import pandas as pd
import numpy as np
def explode_str(df, col, sep):
s = df[col]
i = np.arange(len(s)).repeat(s.str.count(sep) + 1)
return df.iloc[i].assign(**{col: sep.join(s).split(sep)})
def explode_list(df, col):
s = df[col]
i = np.arange(len(s)).repeat(s.str.len())
return df.iloc[i].assign(**{col: np.concatenate(s)})
explode_str(a, 'var1', ',')
var1 var2
0 a 1
0 b 1
0 c 1
1 d 2
1 e 2
1 f 2
Давайте создадим новый dataframe d
, который имеет списки
d = a.assign(var1=lambda d: d.var1.str.split(','))
explode_list(d, 'var1')
var1 var2
0 a 1
0 b 1
0 c 1
1 d 2
1 e 2
1 f 2
Я буду использовать np.arange
с repeat
для создания позиций индекса данных, которые я могу использовать с iloc
.
loc
? Поскольку индекс может быть не уникальным, и использование loc
вернет каждую строку, которая соответствует запрошенному индексу.
values
атрибут и срез? При вызове values
, если весь фрагмент данных находится в одном сплоченном «блоке», Pandas вернет представление массива это «блок». В противном случае Pandas придется собирать новый массив. При мольберге этот массив должен иметь одинаковый тип. Часто это означает возврат массива с dtype, который является object
. Используя iloc
вместо резки атрибута values
, я избавляюсь от необходимости иметь дело с этим.
assign
? Когда я использую assign
, используя одно и то же имя столбца, которое я взорвав, я перезаписываю существующий столбец и сохраняю его позицию в фрейме данных.
В силу используя iloc
на повторных позициях, полученный индекс показывает тот же повторяющийся шаблон. Один повтор для каждого элемента списка или строки. Это можно сбросить с помощью reset_index(drop=True)
Я не хочу преждевременно разделить строки. Поэтому вместо этого я считаю вхождения аргумента sep
, предполагая, что если бы я был разбит, длина результирующего списка была бы больше, чем количество разделителей.
Затем я использую это sep
join
строки split
.
def explode_str(df, col, sep):
s = df[col]
i = np.arange(len(s)).repeat(s.str.count(sep) + 1)
return df.iloc[i].assign(**{col: sep.join(s).split(sep)})
Подобно тому, как для строк, за исключением того, что мне не нужно подсчитывать вхождения sep
, потому что его уже split.
Я использую Numpy's concatenate
, чтобы замять списки вместе.
import pandas as pd
import numpy as np
def explode_list(df, col):
s = df[col]
i = np.arange(len(s)).repeat(s.str.len())
return df.iloc[i].assign(**{col: np.concatenate(s)})
Вот довольно простое сообщение, которое использует метод split
из accessand pandas str
, а затем использует NumPy для выравнивания каждой строки в один массив.
Соответствующие значения извлекаются путем повторения нерасширенный столбец правильное количество раз с np.repeat
.
var1 = df.var1.str.split(',', expand=True).values.ravel()
var2 = np.repeat(df.var2.values, len(var1) / len(df))
pd.DataFrame({'var1': var1,
'var2': var2})
var1 var2
0 a 1
1 b 1
2 c 1
3 d 2
4 e 2
5 f 2