Python Pandas 데이터 토큰 화 오류


343

팬더를 사용하여 .csv 파일을 조작하려고 하는데이 오류가 발생합니다.

pandas.parser.CParserError : 데이터 토큰 화 오류. C 오류 : 3 행에 2 개의 필드가 있어야합니다.

팬더 문서를 읽으려고했지만 아무것도 찾지 못했습니다.

내 코드는 간단합니다.

path = 'GOOG Key Ratios.csv'
#print(open(path).read())
data = pd.read_csv(path)

이 문제를 어떻게 해결할 수 있습니까? csv모듈이나 다른 언어를 사용해야 합니까?

Morningstar 에서 가져온 파일


10
에 의해 작성된 파일을 읽을 때이 오류가 발생하면 pandas.to_csv()열 이름에 '\ r'이 있기 때문일 수 있습니다.이 경우 to_csv ()는 실제로 후속 열 이름을 데이터 프레임의 첫 번째 열에 기록하므로 첫 번째 X 행의 열 수의 차이 이 차이는 C 오류의 원인 중 하나입니다.
user0

9
때때로 "sep"매개 변수를 명시 적으로 제공하면 도움이됩니다. 파서 문제인 것 같습니다.
gilgamash

2
이 오류는 쉼표를 구분 기호로 사용하고 예상보다 많은 쉼표가있는 경우에도 발생할 수 있습니다 (오류 행의 더 많은 필드가 헤더에 정의 됨). 따라서 실수로 추가 필드를 제거하거나 여분의 쉼표를 제거해야합니다. 이 문제를 수동으로 수정하면 오류 줄을 건너 뛸 필요가 없습니다.
tsveti_iko

2
gilgamash의 의견이 도움이되었습니다. 텍스트 편집기 (예 : windows 편집기 또는 notepad ++)에서 csv 파일을 열면 분리에 사용되는 문자를 확인하십시오. 세미콜론이라면 예를 들어보십시오 pd.read_csv("<path>", sep=";"). Excel에서는 데이터를 기본적으로 열에 저장하기 때문에 구분 기호를 제거하므로 검사에 Excel을 사용하지 마십시오.
Julian

@gilgamash의 의견과 관련하여 올바른 방향으로 보냈지 만 제 경우 에는 "sep"매개 변수 를 명시 적으로 지정 하지 않으면 해결되었습니다 .
TheLoneDeranger 23

답변:


515

시도해 볼 수도 있습니다.

data = pd.read_csv('file1.csv', error_bad_lines=False)

이로 인해 문제가되는 줄을 건너 뛸 수 있습니다.


152
error_bad_lines = False를 사용하면 문제가되는 행을 건너 뜁니다.
biobirdman

10
이 답변을 우연히 발견하면 줄에 누락 된 열을 채우는 방법이 expected 8 fields, saw 9있습니까?
Petra Barus

26
더 나은 해결책은 문제가되는 파일을 조사하고 잘못된 행을 읽을 수 있도록 수정하는 것 read_csv입니다. @PetraBarus, 왜 열이없는 CSV 파일에 열을 추가하지 않습니까 (필요한 경우 null 값으로)?
dbliss

4
네, 방금 했어요 열을 추가하면 훨씬 쉽습니다. 스프레드 시트에서 CSV를 열면됩니다.
Petra Barus

5
names=["col1", "col2", ...]최대 예상 열 수를 전달하는 것도 가능 하며,이 문제를 해결할 때이 문제를 해결하는 방법입니다. 다음을 참조하십시오 : stackoverflow.com/questions/18039057/…
Steven Rouk

100

문제 일 수 있습니다

  • 데이터의 구분자
  • @TomAugspurger가 지적한 것처럼 첫 번째 행

이 문제를 해결하려면를 호출 할 때 sep및 / 또는 header인수를 지정하십시오 read_csv. 예를 들어

df = pandas.read_csv(fileName, sep='delimiter', header=None)

위의 코드에서 sep구분자를 정의하고 header=None팬더에게 소스 데이터에 헤더 / 열 제목에 대한 행이 없음을 알려줍니다. 따라서 문서를 말했다 : "파일에 헤더 행이 없으면 명시 적으로 header = None을 전달해야합니다." 이 경우 팬더는 각 필드 {0,1,2, ...}에 대해 정수 인덱스를 자동으로 만듭니다.

문서에 따르면 구분 기호 는 문제 가 되지 않아야합니다. 문서에 따르면 sep가 None [지정되지 않은 경우]이 자동으로 결정됩니다. 그러나 명확한 구분 기호가있는 인스턴스를 포함하여 이것으로 운이 없었습니다.


예, 때로는 구분자가이 문제의 원인 일 수 있습니다. 구분자가 세미콜론 (;) 인 동일한 문제에 직면했습니다.
Anurag Sharma

43

파서가 파일 헤더에 혼동되고 있습니다. 첫 번째 행을 읽고 해당 행의 열 수를 유추합니다. 그러나 처음 두 행은 파일의 실제 데이터를 나타내지 않습니다.

함께 사용해보십시오 data = pd.read_csv(path, skiprows=2)


30

CSV 파일에는 가변 개수의 열이있을 수 있으며 read_csv처음 몇 행의 열 수를 유추했습니다. 이 경우 해결하는 두 가지 방법 :

1) 최대 열 수의 더미 첫 줄을 갖도록 CSV 파일을 변경하고을 지정 header=[0]하십시오.

2) 또는 names = list(range(0,N))N이 최대 열 수인 곳에서 사용 하십시오.


25

csv CSV의 대부분은를 사용하여 생성 sep='/t'되므로 구분 기호 를 read_csv사용하여 탭 문자 (\t)를 사용해보십시오 /t. 따라서 다음 코드 줄을 사용하여 열어보십시오.

data=pd.read_csv("File_path", sep='\t')

5
@MichaelQueue : 이것은 올바르지 않습니다. CSV는 일반적으로 쉼표로 구분되지만 다른 문자로 구분 될 수도 있습니다. CSV 사양을 참조하십시오 . 쉼표, 탭 ( '\ t'), 세미콜론 및 추가 공백 일 수 있습니다. :)
DJGrandpaJ

내 경우에는 구분 기호 문제였습니다. read_csv는 기본적으로 쉼표로 기본 설정되며 쉼표를 포함하는 텍스트 필드가 있으며 데이터는 다른 구분 기호로 저장되었습니다.
user108569

값에 쉼표가 사용되지만 탭이 구분 기호이고 sep가 사용되지 않은 경우 (또는 값에서 발생한다고 가정 한 구분 기호 위에 제안 된대로)이 오류가 발생합니다. 구분 기호가 어떤 값에서도 발생하지 않는지 확인하십시오. 그렇지 않으면 일부 행에 잘못된 수의 열이있는 것으로 보입니다.
demongolem

CSV를 만드는 동안 Excel 2016을 사용하고 sep = ';' 나를 위해 일하십시오
압둘라는

18

나는 또한이 문제가 있었지만 아마도 다른 이유가있을 수 있습니다. 팬더가 읽으려고하는 열을 추가하는 CSV에 후행 쉼표가 있습니다. 다음을 사용하면 작동하지만 잘못된 줄은 무시합니다.

data = pd.read_csv('file1.csv', error_bad_lines=False)

오류를 처리하기 위해 추한 종류의 해킹을 유지하려면 다음과 같은 작업을 수행하십시오.

line     = []
expected = []
saw      = []     
cont     = True 

while cont == True:     
    try:
        data = pd.read_csv('file1.csv',skiprows=line)
        cont = False
    except Exception as e:    
        errortype = e.message.split('.')[0].strip()                                
        if errortype == 'Error tokenizing data':                        
           cerror      = e.message.split(':')[1].strip().replace(',','')
           nums        = [n for n in cerror.split(' ') if str.isdigit(n)]
           expected.append(int(nums[0]))
           saw.append(int(nums[2]))
           line.append(int(nums[1])-1)
         else:
           cerror      = 'Unknown'
           print 'Unknown Error - 222'

if line != []:
    # Handle the errors however you want

위 코드의 변수 'line'에 의해 잘못된 행이 제공되므로 행을 DataFrame에 다시 삽입하는 스크립트를 작성했습니다. 이것은 단순히 CSV 리더를 사용하여 피할 수 있습니다. 팬더 개발자가 앞으로 이러한 상황을보다 쉽게 ​​처리 할 수 ​​있기를 바랍니다.


14

열 이름을 전달하지 않고 CSV로 읽으려고하는이 문제가있었습니다.

df = pd.read_csv(filename, header=None)

미리 목록에 열 이름을 지정한 다음에 전달하여 names즉시 해결했습니다. 열 이름을 설정하지 않은 경우 데이터에있을 수있는 최대 열 수만큼 자리 표시 자 이름을 만들 수 있습니다.

col_names = ["col1", "col2", "col3", ...]
df = pd.read_csv(filename, names=col_names)

1
error_bad_line = False를 사용하는 경우와 비교하여 행이 삭제되지 않기 때문에 더 나은 답변입니다. 또한이 솔루션에서 데이터 프레임을 만든 후에 문제가 된 라인을 쉽게 파악할 수 있습니다.
zipline86

@ zipline86에 동의합니다. 이 답변은 안전하고 지능적입니다.
Monica Heddneck

11

나는이 문제를 몇 번이나 겪었다. 거의 항상, 그 이유는 내가 열려고하는 파일이 처음에 제대로 저장된 CSV가 아니기 때문입니다. 그리고 "적절하게"라는 말은 각 행에 같은 수의 구분 기호 나 열이 있다는 의미입니다.

일반적으로 Excel에서 CSV를 연 다음 부적절하게 저장했기 때문에 발생했습니다. 파일 확장자는 여전히 .csv이지만 순수한 CSV 형식이 변경되었습니다.

pandas to_csv로 저장된 모든 파일은 올바르게 형식이 지정되므로 해당 문제가 발생하지 않아야합니다. 그러나 다른 프로그램으로 열면 구조가 변경 될 수 있습니다.

희망이 도움이됩니다.


8

나는 같은 문제를 겪었다. pd.read_table()동일한 소스 파일에서 사용 하는 것이 효과가있는 것 같습니다. 나는 그 이유를 추적 할 수 없었지만 그것은 내 경우에 유용한 해결책이었습니다. 아마도 더 많은 지식을 가진 사람이 왜 그것이 효과가 있었는지 더 밝힐 수 있습니다.

편집 : 파일에 실제 데이터와 형식이 다른 텍스트가 있으면이 오류가 발생합니다. 이것은 일반적으로 실제 데이터와 동일한 수의 쉼표로 구분되지 않는 헤더 또는 바닥 글 정보 (한 줄 이상이므로 skip_header가 작동하지 않음)입니다 (read_csv 사용시). read_table을 사용하면 탭을 구분 기호로 사용하여 사용자의 현재 오류를 피할 수 있지만 다른 오류를 유발할 수 있습니다.

나는 보통 여분의 데이터를 파일로 읽어서 read_csv () 메소드를 사용 하여이 문제를 해결합니다.

정확한 해결책은 실제 파일에 따라 다를 수 있지만이 방법은 여러 경우에 효과적이었습니다.


6

다음은 저에게 효과적이었습니다 (Google Colaboratory Notebook 에서이 문제가 있었기 때문에이 답변을 게시했습니다).

df = pd.read_csv("/path/foo.csv", delimiter=';', skiprows=0, low_memory=False)

1
|내 .csv의 구분 기호로 설정하지 않을 때 문제를 실험했습니다 . 오히려 줄을 건너 뛰거나 잘못된 줄을 사용하는 대신이 방법을 먼저 시도해보십시오.
ivanleoncz

나도 같은 문제가 있었는데, 기본적으로 "\ t"가 구분자로 감지 될 것이라고 생각했다. 구분 기호를 명시 적으로 "\ t"로 설정했을 때 작동했습니다.
Rahul Jha

5

공백, 쉼표 및 따옴표가있는 탭으로 구분 된 테이블을 읽으려고 할 때 비슷한 문제가 있습니다.

1115794 4218    "k__Bacteria", "p__Firmicutes", "c__Bacilli", "o__Bacillales", "f__Bacillaceae", ""
1144102 3180    "k__Bacteria", "p__Firmicutes", "c__Bacilli", "o__Bacillales", "f__Bacillaceae", "g__Bacillus", ""
368444  2328    "k__Bacteria", "p__Bacteroidetes", "c__Bacteroidia", "o__Bacteroidales", "f__Bacteroidaceae", "g__Bacteroides", ""



import pandas as pd
# Same error for read_table
counts = pd.read_csv(path_counts, sep='\t', index_col=2, header=None, engine = 'c')

pandas.io.common.CParserError: Error tokenizing data. C error: out of memory

이것은 C 파싱 엔진 (기본 엔진)과 관련이 있다고 말합니다. 아마도 파이썬으로 바꾸면 무엇이든지 변할 것입니다.

counts = pd.read_table(path_counts, sep='\t', index_col=2, header=None, engine='python')

Segmentation fault (core dumped)

이제는 다른 오류입니다.
계속해서 테이블에서 공백을 제거하려고하면 python-engine의 오류가 다시 한 번 변경됩니다.

1115794 4218    "k__Bacteria","p__Firmicutes","c__Bacilli","o__Bacillales","f__Bacillaceae",""
1144102 3180    "k__Bacteria","p__Firmicutes","c__Bacilli","o__Bacillales","f__Bacillaceae","g__Bacillus",""
368444  2328    "k__Bacteria","p__Bacteroidetes","c__Bacteroidia","o__Bacteroidales","f__Bacteroidaceae","g__Bacteroides",""


_csv.Error: '   ' expected after '"'

팬더가 행을 파싱하는 데 문제가 있음이 분명합니다. 파이썬 엔진으로 테이블을 파싱하려면 미리 테이블에서 모든 공백과 따옴표를 제거해야했습니다. 한편 C 엔진은 쉼표로도 계속 충돌했습니다.

대체 파일로 새 파일을 만들지 않으려면 테이블이 작기 때문에이 작업을 수행했습니다.

from io import StringIO
with open(path_counts) as f:
    input = StringIO(f.read().replace('", ""', '').replace('"', '').replace(', ', ',').replace('\0',''))
    counts = pd.read_table(input, sep='\t', index_col=2, header=None, engine='python')

tl; dr
구문 분석 엔진을 변경하고 데이터에서 구분되지 않는 따옴표 / 쉼표 / ​​공백을 피하십시오.


5

내가 사용한 데이터 집합에는 서식 외의 많은 따옴표 ( ")가 사용되었습니다.이 매개 변수를 포함하여 오류를 해결할 수있었습니다 read_csv().

quoting=3 # 3 correlates to csv.QUOTE_NONE for pandas

2
똑같은 것을 우연히 발견했습니다. 내가 아는 한, 이것이 정답입니다. 수락 된 것은 오류를 숨 깁니다.
lhk

나에게도 정답. +1
Taha Jirjees

4

매개 변수에 분리 문자 사용

pd.read_csv(filename, delimiter=",", encoding='utf-8')

읽습니다.


3

이 질문의 경우는 아니지만이 오류는 압축 된 데이터와 함께 나타날 수도 있습니다. 명시 적으로 값을 설정하여 kwarg compression문제 를 해결했습니다.

result = pandas.read_csv(data_source, compression='gzip')

3

비슷한 구문 분석 오류를 처리하는 데 유용한 대안은 CSV 모듈을 사용하여 데이터를 팬더 df로 다시 라우팅합니다. 예를 들면 다음과 같습니다.

import csv
import pandas as pd
path = 'C:/FileLocation/'
file = 'filename.csv'
f = open(path+file,'rt')
reader = csv.reader(f)

#once contents are available, I then put them in a list
csv_list = []
for l in reader:
    csv_list.append(l)
f.close()
#now pandas has no problem getting into a df
df = pd.DataFrame(csv_list)

CSV 모듈은 형식이 잘못 된 쉼표로 구분 된 파일에 대해 조금 더 견고하므로 이러한 경로를 통해 이와 같은 문제를 해결하는 데 성공했습니다.


3

다음과 같은 일련의 명령이 작동합니다 (데이터의 첫 번째 줄을 잃습니다-헤더 없음 = 없음). 그러나 적어도로드됩니다.

df = pd.read_csv(filename, usecols=range(0, 42)) df.columns = ['YR', 'MO', 'DAY', 'HR', 'MIN', 'SEC', 'HUND', 'ERROR', 'RECTYPE', 'LANE', 'SPEED', 'CLASS', 'LENGTH', 'GVW', 'ESAL', 'W1', 'S1', 'W2', 'S2', 'W3', 'S3', 'W4', 'S4', 'W5', 'S5', 'W6', 'S6', 'W7', 'S7', 'W8', 'S8', 'W9', 'S9', 'W10', 'S10', 'W11', 'S11', 'W12', 'S12', 'W13', 'S13', 'W14']

다음은 작동하지 않습니다.

df = pd.read_csv(filename, names=['YR', 'MO', 'DAY', 'HR', 'MIN', 'SEC', 'HUND', 'ERROR', 'RECTYPE', 'LANE', 'SPEED', 'CLASS', 'LENGTH', 'GVW', 'ESAL', 'W1', 'S1', 'W2', 'S2', 'W3', 'S3', 'W4', 'S4', 'W5', 'S5', 'W6', 'S6', 'W7', 'S7', 'W8', 'S8', 'W9', 'S9', 'W10', 'S10', 'W11', 'S11', 'W12', 'S12', 'W13', 'S13', 'W14'], usecols=range(0, 42))

CParserError : 데이터 토큰 화 오류. C 오류 : 1605634 행에 53 개의 필드가 예상 되었으나 54 번이 작동하지 않습니다.

df = pd.read_csv(filename, header=None)

CParserError : 데이터 토큰 화 오류. C 오류 : 1605634 행에 53 개의 필드가 예상되었습니다.

따라서 당신의 문제에서 당신은 통과해야합니다 usecols=range(0, 2)


3

Linux OS에서 Python 3과 비슷한 문제가있는 사람들을 위해.

pandas.errors.ParserError: Error tokenizing data. C error: Calling
read(nbytes) on source failed. Try engine='python'.

시험:

df.read_csv('file.csv', encoding='utf8', engine='python')

2

때로는 문제는 파이썬을 사용하는 방법이 아니라 원시 데이터와 관련이 있습니다.
이 오류 메시지가 나타납니다

Error tokenizing data. C error: Expected 18 fields in line 72, saw 19.

열 설명에 때로는 쉼표가있는 것으로 나타났습니다. 즉, CSV 파일을 정리하거나 다른 구분 기호를 사용해야합니다.



1

기존 행 번호가있는 데이터 세트가 있었고 index_col을 사용했습니다.

pd.read_csv('train.csv', index_col=0)

1

이것이 내가 한 일입니다.

sep='::' 내 문제를 해결했습니다.

data=pd.read_csv('C:\\Users\\HP\\Downloads\\NPL ASSINGMENT 2 imdb_labelled\\imdb_labelled.txt',engine='python',header=None,sep='::')

1

나는 이것과 비슷한 사건을 가지고 있었고

train = pd.read_csv('input.csv' , encoding='latin1',engine='python') 

일했다


1

read_csv : ParserError : 데이터 토큰 화 오류와 동일한 문제가 있습니다. 방금 이전 csv 파일을 새 csv 파일로 저장했습니다. 문제가 해결되었습니다!


1

나를 위해 문제는 하루 종일 내 CSV에 새 열이 추가되었다는 것 입니다. 내가 사용한 경우 모든 미래 행이 삭제되므로 허용 된 답변 솔루션이 작동하지 않습니다.error_bad_lines=False .

이 경우의 해결책은의 usecols 매개 변수 를 사용하는 입니다 pd.read_csv(). 이렇게하면 CSV로 읽어야 할 열만 지정할 수 있으며 헤더 열이 있고 열 이름이 변경되지 않는 한 Python 코드는 향후 CSV 변경에 탄력적입니다.

usecols : list-like or callable, optional 

Return a subset of the columns. If list-like, all elements must either
be positional (i.e. integer indices into the document columns) or
strings that correspond to column names provided either by the user in
names or inferred from the document header row(s). For example, a
valid list-like usecols parameter would be [0, 1, 2] or ['foo', 'bar',
'baz']. Element order is ignored, so usecols=[0, 1] is the same as [1,
0]. To instantiate a DataFrame from data with element order preserved
use pd.read_csv(data, usecols=['foo', 'bar'])[['foo', 'bar']] for
columns in ['foo', 'bar'] order or pd.read_csv(data, usecols=['foo',
'bar'])[['bar', 'foo']] for ['bar', 'foo'] order.

my_columns = ['foo', 'bar', 'bob']
df = pd.read_csv(file_path, usecols=my_columns)

이것의 또 다른 장점은 18-20 개의 열이있는 CSV의 3-4 열만 사용하는 경우 데이터를 메모리에 덜로드 할 수 있다는 것입니다.


1

간단한 해결 방법 : csv 파일을 Excel로 열고 다른 이름의 csv 형식으로 저장하십시오. 다시 스파이더 가져 오기를 시도하면 문제가 해결됩니다!


1

길잃은 따옴표와 함께이 오류가 발생했습니다. 쉼표로 구분 된 파일을 내보낼 때 텍스트 항목을 따옴표로 묶는 매핑 소프트웨어를 사용합니다. 구분 기호 충돌을 유발할 때 따옴표 (예 : '= feet 및 "= inch)를 사용하는 텍스트는 문제가 될 수 있습니다.이 예에서는 5 인치 우물 로그 인쇄 품질이 낮음을 나타냅니다.

UWI_key,Latitude,Longitude,Remark US42051316890000,30.4386484,-96.4330734,"poor 5""

작업에 렌치를 던지는 결말 5"로 사용 5 inch합니다. Excel은 단순히 추가 따옴표를 제거하지만 error_bad_lines=False위에서 언급 한 인수 없이 Pandas가 분류됩니다 .


1

내가 알 수있는 한, 파일을 살펴본 후에 문제는로드하려는 csv 파일에 여러 테이블이 있다는 것입니다. 빈 줄이나 표 제목이있는 줄이 있습니다. 이 Stackoverflow 답변을 살펴보십시오 . 프로그래밍 방식으로 달성하는 방법을 보여줍니다.

csv 모듈 을 사용하는 또 다른 동적 접근법 한 번에 모든 단일 행을 읽고 위생 검사 / 정규 표현식을 작성하여 행이 (제목 / 헤더 / 값 / 공백) 여부를 추론하는 입니다. 이 접근 방식의 장점은 파이썬 객체에서 원하는대로 데이터를 분할 / 추가 / 수집 할 수 있다는 것입니다.

가장 쉬운 방법은 pd.read_clipboard()CSV를 Excel 등으로 열 수있는 경우 수동으로 테이블을 선택하고 클립 보드에 복사 한 후 팬더 기능을 사용하는 것입니다.

관련이 없음 :

또한 문제관련이 없지만 아무도 언급하지 않았기 때문에seeds_dataset.txt UCI 와 같은 일부 데이터 세트를로드 할 때도 동일한 문제가 발생했습니다 . 필자의 경우 일부 구분 기호에 실제 탭보다 공백이 많기 때문에 오류가 발생했습니다 \t. 예를 들어 다음의 3 행을 참조하십시오.

14.38   14.21   0.8951  5.386   3.312   2.462   4.956   1
14.69   14.49   0.8799  5.563   3.259   3.586   5.219   1
14.11   14.1    0.8911  5.42    3.302   2.7     5       1

따라서 . \t+대신 구분 기호 패턴을 사용하십시오 \t.

data = pd.read_csv(path, sep='\t+`, header=None)

1

필자의 경우 csv 파일의 첫 번째와 마지막 두 줄의 형식이 파일의 중간 내용과 다르기 때문입니다.

그래서 내가하는 일은 csv 파일을 문자열로 열고 문자열의 내용을 구문 분석 한 다음 read_csv데이터 프레임을 얻는 데 사용 하는 것입니다.

import io
import pandas as pd

file = open(f'{file_path}/{file_name}', 'r')
content = file.read()

# change new line character from '\r\n' to '\n'
lines = content.replace('\r', '').split('\n')

# Remove the first and last 2 lines of the file
# StringIO can be considered as a file stored in memory
df = pd.read_csv(StringIO("\n".join(lines[2:-2])), header=None)

1

필자의 경우 구분 기호는 기본 ""이 아니라 Tab입니다.

pd.read_csv(file_name.csv, sep='\\t',lineterminator='\\r', engine='python', header='infer')

참고 : "\ t"는 일부 소스에서 제안한대로 작동하지 않았습니다. "\\ t"가 필요했습니다.


0

비슷한 오류가 있었고 문제는 CSV 파일에 이스케이프 된 따옴표가 있고 escapechar 매개 변수를 적절하게 설정해야한다는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.